型テスト
サンプルプロジェクト
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」型 (https://github.com/microsoft/TypeScript/pull/40468) のサポートを追加すれば、これらのエラーメッセージは大幅に改善される可能性があります。それまでは、ある程度の注意深い確認が必要となります。
具体的な「期待される」オブジェクト vs 型引数
次のようなアサーションのエラーメッセージ:
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
を使用するため、これらのスクリプトをパイプラインから削除することが可能です。