型テスト
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 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}>()
報告される型制約は、"expected" と "actual" の両方の型を指定する、人間が読みやすいメッセージである点に留意してください。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」型をサポートした場合、これらのエラーメッセージは大幅に改善される可能性があります。それまでは、ある程度の注意深い確認が必要となるでしょう。
具体的な「期待される」オブジェクトと型引数
次のようなアサーションのエラーメッセージ:
expectTypeOf({ a: 1 }).toEqualTypeOf({ a: '' });
は、次のようなアサーションよりも有用ではありません。
expectTypeOf({ a: 1 }).toEqualTypeOf<{ a: string }>();
これは、TypeScript コンパイラが .toEqualTypeOf({a: ''})
スタイルの型引数を推論する必要があり、このライブラリはそれを汎用的な Mismatch
型と比較することによってのみ失敗として扱うことができるためです。したがって、可能な場合は、.toEqualTypeOf
および toMatchTypeOf
には具体的な型ではなく型引数を使用するようにしてください。2 つの具体的な型を比較する方がはるかに便利な場合は、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); //
型チェックの実行
型チェックを有効にするには、package.json
の Vitest コマンドに --typecheck
フラグを追加してください。
{
"scripts": {
"test": "vitest --typecheck"
}
}
これで型チェックを実行できます。
npm run test
yarn test
pnpm run test
bun test
Vitest は、設定に応じて tsc --noEmit
または vue-tsc --noEmit
を使用するため、これらのスクリプトをパイプラインから削除することができます。