6.7 さらに高度な型
この節では、普段から頻繁に使用するわけではないものの、TypeScriptの表現力を極限まで高めるための非常に高度な型機能について表面をなぞる程度に解説します。
6.7.1 object型 never型
Section titled “6.7.1 object型 never型”object型: 「プリミティブ以外のすべて(オブジェクト)」を表す型です。単体ではプロパティにアクセスできないため不便ですが、HasToString & objectのようにインターセクション型と組み合わせることで、「メソッドを持つがプリミティブではない値」に制限したい場合などに役立ちます。never型: 「当てはまる値が存在しない」ことを表す型です。never型の引数を要求する関数は呼び出すことができず、またnever型を返す関数は「必ず例外を投げて大域脱出する(正常に終了しない)関数」を意味します。
6.7.2 型述語(ユーザー定義型ガード)
Section titled “6.7.2 型述語(ユーザー定義型ガード)”typeof などの単純な条件ではなく、複雑なロジックで型の絞り込みを行いたい場合に自身で定義する特殊な関数です。
- 構文: 戻り値の型として
引数名 is 型またはasserts 引数名 is 型を指定します。 - 危険性と責任: ユーザー定義型ガードは
anyやasと同じく型安全性を破壊し得る危険な機能です。関数内の絞り込みロジックが正しいかどうかはコンパイラではなくプログラマーが責任を持つ必要があります。 - メリット: 危険な機能の中では最も「何を保証すべきか(ロジックの正当性)」が明確であり、
anyを使うくらいならユーザー定義型ガードで代替すべきです。
6.7.3 可変長タプル型
Section titled “6.7.3 可変長タプル型”タプル型の中に ...(スプレッド構文)に似た要素を含めることができる機能です。
- 構文例:
[number, ...string[]]のように記述し、「最初の要素がnumberで、それ以降は0個以上のstringが続く配列」を表現できます。 - 応用:
[string, ...NSN, string]のように、既存のタプル型(NSN)を展開して新しいタプル型を作ることも可能です。
6.7.4 mapped types
Section titled “6.7.4 mapped types”既存の型のプロパティ名(ユニオン型など)をループ処理のように展開し、新しいオブジェクト型を作り出す機能です。
- 構文例:
{[P in K]: T}。 - 挙動: ユニオン型
K(例:"apple" | "orange")の各要素Pに対して、型T(例:number)を持つプロパティを生成します。
6.7.5 conditional types
Section titled “6.7.5 conditional types”型の条件分岐を行う機能で、TypeScriptの「型レベルプログラミング」を支える強力な仕組みです。
- 構文:
X extends Y ? S : T(XがYの部分型ならばS型、そうでなければT型)。 - Union Distribution:
Xがユニオン型の場合、条件分岐がそれぞれの型に分配されて評価されるという特殊な性質を持ちます。
6.7.6 組み込みの型を使いこなす
Section titled “6.7.6 組み込みの型を使いこなす”高度な mapped types や conditional types を自身で書かなくても、標準ライブラリにはよく使われる便利な型(ユーティリティ型)があらかじめ用意されています。
- オブジェクトの加工:
Readonly<T>: すべてのプロパティを読み取り専用(readonly)にする。Partial<T>: すべてのプロパティをオプショナル(?)にする。Required<T>: すべてのプロパティを必須(オプショナルを外す)にする。Pick<T, K>: 指定したプロパティKのみを抜き出す。Omit<T, K>: 指定したプロパティKを除外する。
- ユニオン型の加工:
Extract<T, U>: ユニオン型Tのうち、Uに当てはまるものだけを抽出する。Exclude<T, U>: ユニオン型Tから、Uに当てはまるものを除外する。NonNullable<T>: 型Tからnullとundefinedを除外する。