타입 테스트
Vitest에서는 expectTypeOf
또는 assertType
구문을 사용하여 타입 테스트를 작성할 수 있습니다. 기본적으로 *.test-d.ts
파일 내의 모든 테스트는 타입 테스트로 간주되지만, typecheck.include
설정 옵션을 통해 이를 변경할 수 있습니다.
Vitest는 내부적으로 설정에 따라 tsc
또는 vue-tsc
를 호출하고 그 결과를 분석합니다. 또한, 소스 코드에서 타입 오류를 발견하면 이를 출력합니다. typecheck.ignoreSourceErrors
설정 옵션을 사용하여 이 기능을 비활성화할 수 있습니다.
Vitest는 이러한 파일을 실행하거나 컴파일하지 않고, 컴파일러에 의해 정적으로 분석하므로 동적 문법은 사용할 수 없습니다. 즉, 동적인 테스트 이름이나 test.each
, test.runIf
, test.skipIf
, test.concurrent
API는 사용할 수 없습니다. 그러나 test
, describe
, .only
, .skip
및 .todo
와 같은 다른 API는 사용할 수 있습니다.
--allowOnly
및 -t
와 같은 CLI 플래그도 타입 검사에서 지원됩니다.
import { assertType, expectTypeOf } from 'vitest';
import { mount } from './mount.js';
test('my types work properly', () => {
expectTypeOf(mount).toBeFunction();
expectTypeOf(mount).parameter(0).toMatchTypeOf<{ name: string }>();
// @ts-expect-error name is a string
assertType(mount({ name: 42 }));
});
테스트 파일 내에서 발생하는 모든 타입 오류는 테스트 실패로 처리되므로, 프로젝트의 타입 테스트를 위해 다양한 방법을 활용할 수 있습니다.
API 섹션에서 사용 가능한 매처 목록을 확인할 수 있습니다.
오류 분석
expectTypeOf
API를 사용하는 경우, 오류 메시지에 대한 expect-type 문서를 참조하십시오.
타입이 일치하지 않으면 .toEqualTypeOf
및 .toMatchTypeOf
는 가능한 한 이해하기 쉬운 오류 메시지를 생성하기 위해 특수한 헬퍼 타입을 사용합니다. 그러나 주의해야 할 미묘한 차이가 있습니다. 단언문이 '체이닝 방식'으로 작성되기 때문에 오류는 "실제" 타입이 아닌 "예상" 타입에서 발생합니다 (expect<Actual>().toEqualTypeOf<Expected>()
). 이는 타입 오류가 다소 혼란스러울 수 있음을 의미하므로, 이 라이브러리는 기대값을 명확하게 표현하기 위해 MismatchInfo
타입을 생성합니다. 예를 들어:
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
{a: 1}
은 {a: number}
타입을 가지며 {a: string}
타입을 가지지 않기 때문에 실패하는 단언문입니다. 이 경우 오류 메시지는 다음과 같이 표시됩니다.
test/test.ts:999:999 - error TS2344: Type '{ a: string; }' does not satisfy the constraint '{ a: \\"Expected: string, Actual: number\\"; }'.
Types of property 'a' are incompatible.
Type 'string' is not assignable to type '\\"Expected: string, Actual: number\\"'.
999 expectTypeOf({a: 1}).toEqualTypeOf<{a: string}>()
보고된 타입 제약은 '예상' 타입과 '실제' 타입을 모두 포함하는 읽기 쉬운 메시지입니다. Types of property 'a' are incompatible // Type 'string' is not assignable to type "Expected: string, Actual: number"
문장을 그대로 해석하기보다는 속성 이름 ('a'
)과 메시지 Expected: string, Actual: number
를 살펴보십시오. 이것은 대부분의 경우 무엇이 잘못되었는지 알려줍니다. 매우 복잡한 타입의 경우 디버깅에 더 많은 노력이 필요하며 약간의 실험이 필요할 수 있습니다. 오류 메시지가 실제로 오해를 불러일으키는 경우 이슈를 제기하십시오.
toBe...
메서드 (toBeString
, toBeNumber
, toBeVoid
등)는 테스트 중인 Actual
타입이 일치하지 않을 때 호출 불가능한 타입으로 확인되어 실패합니다. 예를 들어 expectTypeOf(1).toBeString()
과 같은 단언문의 실패는 다음과 같이 나타날 수 있습니다.
test/test.ts:999:999 - error TS2349: This expression is not callable.
Type 'ExpectString<number>' has no call signatures.
999 expectTypeOf(1).toBeString()
~~~~~~~~~~
This expression is not callable
부분은 그다지 유용하지 않습니다. 의미 있는 오류는 다음 줄인 Type 'ExpectString<number> has no call signatures
입니다. 이는 숫자를 전달했지만 문자열이어야 한다고 주장했음을 의미합니다.
TypeScript가 "throw" 타입에 대한 지원을 추가하면 이러한 오류 메시지를 크게 개선할 수 있습니다. 그때까지는 어느 정도 주의 깊게 살펴봐야 할 것입니다.
구체적인 "예상" 객체 vs 타입 인자
다음과 같은 단언문에 대한 오류 메시지:
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' });
다음과 같은 단언문보다 이해하기 어려울 수 있습니다.
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
이는 TypeScript 컴파일러가 .toEqualTypeOf({a: ''})
스타일에 대한 타입 인자를 추론해야 하고, 이 라이브러리는 일반적인 Mismatch
타입과 비교하여 실패로 표시할 수 있기 때문입니다. 따라서 가능한 경우 .toEqualTypeOf
및 .toMatchTypeOf
에 대해 구체적인 타입 대신 타입 인자를 사용하는 것이 좋습니다. 두 개의 구체적인 타입을 비교하는 것이 훨씬 더 편리한 경우 typeof
를 사용할 수 있습니다.
const one = valueFromFunctionOne({ some: { complex: inputs } });
const two = valueFromFunctionTwo({ some: { other: inputs } });
expectTypeOf(one).toEqualTypeOf<typeof two>();
expectTypeOf
API로 작업하는 데 어려움이 있거나 오류를 파악하기 어려운 경우, 더 간단한 assertType
API를 사용할 수 있습니다.
const answer = 42;
assertType<number>(answer);
// @ts-expect-error answer is not a string
assertType<string>(answer);
TIP
@ts-expect-error
구문을 사용할 때는 오타가 없는지 확인하는 것이 좋습니다. test.include
설정 옵션에 타입 파일을 포함하여 Vitest가 실제로 이러한 테스트를 실행하고 ReferenceError
로 실패하도록 할 수 있습니다.
다음은 오류를 예상했기 때문에 통과하지만, "answer"라는 단어에 오타가 있어 실제 오류를 감지하지 못하는 경우입니다.
// @ts-expect-error answer is not a string
assertType<string>(answr); //
타입 검사 실행하기
Vitest 1.0부터 타입 검사를 활성화하려면 package.json
에서 Vitest 명령에 --typecheck
플래그를 추가하면 됩니다.
{
"scripts": {
"test": "vitest --typecheck"
}
}
이제 타입 검사를 실행할 수 있습니다.
npm run test
yarn test
pnpm run test
bun test
Vitest는 설정에 따라 tsc --noEmit
또는 vue-tsc --noEmit
를 사용하므로, 워크플로우에서 이러한 스크립트를 제거할 수 있습니다.