タイトルがよくわからなくなっちゃいました
個人の備忘録的に記事にいたします。
構文例
以下の構文を例にしてみます。
type First<T extends unknown[]> = T extends never[] ? never : T[0]
この First<>
は T が never[] の場合、never型 になります。
それ以外は、T[]の最初だけの型 になります。
これは、TypeScript の Conditional Types と呼ばれるものです。
解説
コードの以下の部分に注目いたします。
T extends never[] ? never : T[0]
ここでの T
は Generic で受け取る型になります。
そして、T extends never[] ?
の部分は、
T が never[] を継承しているかどうかの判定になります。
そこから後は 真の場合 : 偽の場合
です。
三項演算子と同様の記法ですね。
条件分岐地獄
ちなみに、この条件分岐をつなげていくこともできます。
以下は公式にあった例です。
type TypeName<T> = T extends string
? "string"
: T extends number
? "number"
: T extends boolean
? "boolean"
: T extends undefined
? "undefined"
: T extends Function
? "function"
: "object";
type T0 = TypeName<string>; // "string"
type T1 = TypeName<"a">; // "string"
type T2 = TypeName<true>; // "boolean"
type T3 = TypeName<() => void>; // "function"
type T4 = TypeName<string[]>; // "object"
おっっふ!!!!
一緒によく使われるinferについて
最後は、Conditional Types とよく一緒に使われる、inferについてです。
とても簡単に言うと、「Conditional Types の構文の中で型をキャプチャする機能」です。
以下、構文例です。
type Awaited<T extends Promise<unknown>> = T extends Promise<infer R> ? R : never
解説
上記の解説です。
まず、以下の部分です。
T extends Promise<infer R> ?
T extends Promise
なので、T が Promise型であるかどうかの判定になります。
Promise<infer R>
は
以下の例を参考にしてみます。
type Hoge = Promise<string>
type Foo = Awaited<Hoge> // "string"
この場合は、Promise<string>
の <string>
の部分を R にキャプチャしています。
そして、Promise型であるため、R を返している、つまり string になります。
ドキュメント
以上になります。