타입 검사
Vitest는 expectTypeOf
또는 assertType
구문을 사용하여 타입 테스트를 작성할 수 있도록 지원합니다. 기본적으로 *.test-d.ts
파일 내의 모든 테스트는 타입 테스트로 간주되지만, typecheck.include
설정 옵션을 통해 이 동작을 변경할 수 있습니다.
Vitest는 내부적으로 설정에 따라 tsc
또는 vue-tsc
를 호출하고 그 결과를 파싱합니다. Vitest는 소스 코드에서 타입 오류를 발견하면 이를 보고합니다. typecheck.ignoreSourceErrors
설정 옵션을 사용하여 이 보고를 비활성화할 수 있습니다.
Vitest는 이 파일들을 직접 실행하지 않고 컴파일러에 의한 정적 분석만 수행한다는 점을 유의하십시오. 이는 동적 이름이나 test.each
또는 test.for
를 사용하는 경우 테스트 이름이 평가되지 않고 그대로 표시됨을 의미합니다.
WARNING
Vitest 2.1 이전에는 typecheck.include
가 include
패턴을 재정의하여 런타임 테스트가 실제로 실행되지 않고 타입 검사만 이루어졌습니다.
Vitest 2.1부터는 include
와 typecheck.include
가 겹칠 경우 Vitest는 타입 테스트와 런타임 테스트를 별도의 항목으로 보고합니다.
--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은 문자열입니다.
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는 문자열이 아닙니다.
assertType<string>(answer);
TIP
@ts-expect-error
구문을 사용할 때, 오타가 없는지 확인하는 것이 좋습니다. 타입 파일을 test.include
설정 옵션에 포함함으로써 Vitest가 실제로 이 테스트를 _실행_하고 ReferenceError
로 실패하도록 할 수 있습니다.
이는 오류를 예상하기 때문에 통과하지만, "answer"라는 단어에 오타가 있어 거짓 양성(false positive) 오류입니다:
// @ts-expect-error answer는 문자열이 아닙니다.
assertType<string>(answr); //
타입 검사 실행
타입 검사를 활성화하려면 package.json
의 Vitest 명령에 --typecheck
플래그를 추가하면 됩니다:
{
"scripts": {
"test": "vitest --typecheck"
}
}
이제 타입 검사를 실행할 수 있습니다:
npm run test
yarn test
pnpm run test
bun test
Vitest는 설정에 따라 tsc --noEmit
또는 vue-tsc --noEmit
를 사용하기 때문에, 파이프라인에서 이러한 스크립트를 제거할 수 있습니다.