LoginSignup
57
23

More than 3 years have passed since last update.

TypeScriptで型のユニットテストをしたい

Last updated at Posted at 2018-08-10

やり方

準備

test.ts
export type TypeEq<A, B> = (<T>() => T extends A ? 1 : 2) extends (<
  T
>() => T extends B ? 1 : 2)
  ? true
  : false

export function assertType<_T extends true>() {}
export function assertNotType<_T extends false>() {}

色々複雑になっていますが、これは any や union、never などに対応するためです。
ここらへんの型は少し特殊なため、このようにしないと正常にテスト出来ません。

テストの書き方

assertType<TypeEq<1, 1>>()
assertNotType<TypeEq<1, 2>>()

テストが正しくなければコンパイルエラーが発生します。

import { TypeEq, assertType, assertNotType } from "./test"

assertType<TypeEq<1, 1>>()
assertNotType<TypeEq<{}, { x: 1 }>>()
assertNotType<TypeEq<1, 2>>()
assertNotType<TypeEq<1 | 2, 1>>()
assertNotType<TypeEq<1, never>>()
assertType<TypeEq<never, never>>()
assertNotType<TypeEq<1, any>>()
assertType<TypeEq<any, any>>()
assertNotType<TypeEq<1, unknown>>()
assertType<TypeEq<unknown, unknown>>()

そもそも何でこんなものが必要なの?

通常の TS の使い方なら必要ありません。
しかし、ts2.1 で Mapped types が入り、ts2.8 で Conditional Types が入り、ts3.0 で Tuple 関連の型システムが強化され TS の型システムはより複雑に、そして高機能になっています。
このような型システムをフル活用すると例えばタプル型をReverseZipするといったとても複雑な事を行えます。[参考](例えばZip<[1,2,3],[10,20]>は型[[1,10],[2,20]]を返すなど)
つまりtypeをただの型エイリアスではなく「型を受け取り型を返す関数」として使うことができます。
当然中身はかなり複雑ですし、バグも発生します。
関数のようなものなので正しい値を返してくれるかのテストを行いたいのです。

例えばさっきの例なら

assertType<TypeEq<Zip<[1, 2, 3], [10, 20]>, [[1, 10], [2, 20]]>>()

のように書くことでテストを行えます。

57
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
23