Conditional Typesとは
Conditional Typesは型のif文です。指定された型をチェックしてその型の条件に応じて、別々の型を返すことができます。
構文は三項演算子に似ていて、
A extends B ? C : D
で、型Aを型Bとみなせるとき、型Cを返す。みなせない場合はDを返す。
というような意味になります
function func<T extends string | number>(arg: T):T {
return arg
}
// 上記の関数の引数の型から返り値の型を推論する型関数を書くと以下のような感じになる
type ReturnType<Arg> = Arg extends string ? string : number
ReturnType<'aaa'> // => string
ReturnType<0> // => number
継承が絡む場合も同じような挙動になります
class Animal {
}
class Dog extends Animal {
}
type Example1 = Dog extends Animal ? number : string; // => number
type Example2 = RegExp extends Animal ? number : string; // => string
Mapped Typesとは
Mapped Typesは、連想配列を作成できる構文です。 {[型変数名 in 型A]: 型B}
のような構文を書くことで、
型Aに指定されたものをキーに持つ連想配列を作成できます。
型Aは多くの場合string
型か文字列リテラルが指定され、string
型の場合は自由な文字列のキーを持つ連想配列を表し、文字列リテラルが指定された場合はその文字列リテラルで指定された文字列のキーのみを持つ連想配列を返します
type A = {
[key in 'a' | 'b']: boolean
};
// => {
// 'a': boolean
// 'b': boolean
// }
type B = {
[key in string]: boolean
}
// => Record<string. boolean> と同じ
前回紹介したRecord
型との違いは、連想配列のキーとバリューの間に関係性をもたせられる点です。
バリュー側の型の中でキーの型を参照できるので、キーの型の条件に応じてバリュー側の型を変えることができます。
type B = {
[key in 'a' | 'b']: key extends 'a' ? 'a' : 'b'
};
// => type B = {
// a: "a";
// b: "b";
// }
この機能を応用すると、特定の型のメンバだけを抽出する型関数を作れたりします。
かなり応用の幅が広い機能なので、型パズルに興味がある人は色々試してみるのもいいかもしれません。