この記事はTypeScript Advent Calendar 2019 の 16日目の記事です。
「Mapped types」,「Conditional Types」などTypeScriptの型システムは高機能です。 しかし、高機能がゆえに複雑で直感的には分かりくい型を生み出していることも事実です。
TypeScriptの型定義は型を返す関数として扱うことができ、型がバグを生み出す原因にもなります。 そんな型でのバグをなくすために型のユニットテストを紹介します。
tsd
型をテストするためにtsdというライブラリを使用します。
tsdはexpectType
,expectError
などの様々なアサーションで型定義をチェックすることができます。
テスト
今回はjestを使ってテストを行うのでtsdとjestに関連するライブラリを用意します。
yarn add -D tsd jest ts-jest @types/jest
package.json
次にpackage.jsonを編集します。
jestの設定を書いていきます。
{
"name": "tsd-unit-testing",
"scripts": {
"test": "jest",
},
"jest": {
"preset": "ts-jest",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"testMatch": [
"**/test-dts/*.(ts|tsx|js)"
]
},
"devDependencies": {
"@types/jest": "^24.0.23",
"jest": "24.9.0",
"ts-jest": "24.2.0",
"tsd": "0.11.0",
"typescript": "^3.7.3",
},
}
型定義
次に今回テストする型定義を準備します。
「TがUに含まれていればTを、そうでなければunknown」を返すConditional Typesです
export type Condition<T, U> = T extends U ? T : unknown;
テストを書く
実際にテストを書いていきます。
expectType
はジェネリクスで指定した型が引数で指定した値と同じかを検査します。
以下の例では'kuma'
型は'inu' | 'neko'
型のUnion Typeには存在しないのでunknown型が返ってくるためテストは通ります🎉
import { expectType } from 'tsd';
import { Condition } from './types'
describe('Check type definitions', () => {
it('Condition', () => {
let animal: Condition<'kuma', 'inu' | 'neko'>
expectType<unknown>(animal)
})
});
❯ yarn test
$ jest
PASS test-dts/type.test-d.ts
Check type definitions
✓ Condition (1ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.715s
Ran all test suites.
✨ Done in 7.07s.
おわりに
他にもいくつかアサーションが用意されているので気になる方はドキュメントをどうぞ!
普通に書いていると高度で複雑な型はあまり出てこないですが、ライブラリを作る際には活用できるかもしれません。(vue-nextで使っているのを観測しました)
余談
昔、tsdというTypeSciptの型定義管理ツールがあったらしいですね...
\ SHARE /