🎃

TypeScript の Conditional Types で複数条件をマージする

2020/12/29に公開

TypeScript の Conditional Types 便利ですね。

この記事を読んでいる方はご存知のことと思いますが一応説明を入れておくと、Conditional Types は型定義における条件分岐です。
型 T をとって、それが文字列型と互換性があるかどうかを返す IsString は以下のように書くことができます。

type IsString<T> = T extends string ? true : false

type A = IsString<'a'>     // type A = true
type B = IsString<1>       // type B = false
type C = IsString<boolean> // type C = false

三項演算子のような見た目で、ネストもできます。
型 T, U をとって、それらすべてが文字列型と互換性があるかどうかを返す IsAllString は以下のように書くことができます。

type IsAllString<T, U> = T extends string
  ? U extends string
    ? true
    : false
  : false

type A = IsAllString<'a', 'b'>  // type A = true
type B = IsAllString<'a', 2>    // type B = false
type C = IsAllString<true, 'b'> // type C = false
type D = IsAllString<true, 2>   // type D = false

IsAllString は実際には T と U の両方が文字列型と互換性があるかどうかを一度にチェックしたいはずですが、この例では 2 回条件分岐を使っています。

そこで Tuple を使って以下のように書き換えます。

type IsAllString<T, U> = [T, U] extends [string, string] ? true : false

type A = IsAllString<'a', 'b'>  // type A = true
type B = IsAllString<'a', 2>    // type B = false
type C = IsAllString<true, 'b'> // type C = false
type D = IsAllString<true, 2>   // type D = false

ミソはT extends stringU extends string[T, U] extends [string, string]にまとめたところです。
これで複数の条件分岐を AND 条件としてまとめることができました。

Discussion