測試類型
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。 但是您可以使用其他 API,例如 test
、describe
、.only
、.skip
和 .todo
。
類型檢查也支援使用 CLI 旗標,例如 --allowOnly
和 -t
。
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
。 在大多數情況下,這會告訴您哪裡發生錯誤。 對於極其複雜的類型,當然需要花費更多精力進行除錯,並且可能需要一些實驗。 如果錯誤訊息具有誤導性,請提出 issue。
當被測試的 Actual
類型不符時,toBe...
方法 (例如 toBeString
、toBeNumber
、toBeVoid
等) 會解析為不可呼叫的類型並產生錯誤。 例如,像 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" types 的支援,這些錯誤訊息可以得到顯著改善。 在那之前,可能需要仔細推敲才能理解這些訊息。
具體的「預期」物件 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 開始,若要啟用類型檢查,只需將 --typecheck
標記加入到 package.json
中的 Vitest 命令:
{
"scripts": {
"test": "vitest --typecheck"
}
}
現在您可以執行類型檢查了:
npm run test
yarn test
pnpm run test
bun test
Vitest 使用 tsc --noEmit
或 vue-tsc --noEmit
,具體取決於您的配置,因此您可以從您的管線中移除這些指令碼。