テストの種類
Vitestでは、`expectTypeOf`または`assertType`構文を使用して、型に対するテストを作成できます。デフォルトでは、`*.test-d.ts`ファイル内のすべてのテストは型テストと見なされますが、`typecheck.include`設定オプションで変更できます。
Vitestは内部的に、設定に応じて`tsc`または`vue-tsc`を呼び出し、結果を解析します。Vitestは、型エラーが見つかった場合、ソースコード内の型エラーも出力します。`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
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}>()
報告された型制約は、「期待される」型と「実際の」型の両方を指定する人間が読めるメッセージであることに注意してください。文`プロパティ 'a' の型が互換性がない // 型 'string' は型 'Expected: string, Actual: number'`を文字通り受け取るのではなく、プロパティ名(`'a'`)とメッセージ:`Expected: string, Actual: number`を確認してください。これにより、ほとんどの場合、何が間違っているかがわかります。非常に複雑な型は、もちろんデバッグに多くの労力を要し、いくつかの実験が必要になる場合があります。エラーメッセージが実際に誤解を招くものである場合は、issueを報告してください。
`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()
~~~~~~~~~~
`この式は呼び出し可能ではありません`の部分はあまり役に立ちません。意味のあるエラーは次の行、`型 'ExpectString
TypeScriptが「スロー」型のサポートを追加した場合、これらのエラーメッセージは大幅に向上する可能性があります。それまでは、ある程度の注意が必要です。
具体的な「期待される」オブジェクトと型引数
次のようなアサーションのエラーメッセージ
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)
ヒント
`@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`を使用するため、これらのスクリプトをパイプラインから削除できます。