分配型(Distributive Types)は、条件付き型(T extends U ? X : Y)を使用する際にTypeScriptにおいて現れる特徴です。左側の型変数がユニオンである場合、TypeScriptは条件をユニオンの各要素に分配します。
例:
// "Test<A> | Test<B> | Test<C>" type Test<T> = T extends string ? () => string : () => number; type Result = Test<'A' | 'B' | 'C'>;
ここでResultは次のように分配されます:
使用される場面 — ユニバーサルAPIの実装、ユニオンに対する操作、例えばフィルタリングやパターンマッチングのために。
特徴:
[T]で囲むと、分配は行われません。これは分配を「オフ」にする方法です。質問: 型 T[] extends number[] ? true : false は分配型になりますか?
正しい答え: いいえ、分配は左側が配列やタプルでなく型変数である場合にのみ起こります。例えば、条件付き型 T extends number ? ... は分配されますが、T[] extends number[] ? ... はそうではありません。
ストーリー
プロジェクト: Reactコンポーネントのpropsを検証するライブラリ。ユニオンpropsを厳密なインターフェイスに変えようとしましたが、分配の知識が不足していたため、型が予想外に複雑になりました(ユニオンメンバーのプロパティが混ざってしまいました)。分配を防ぐために、ラップ
[T]を追加して修正しました。
ストーリー
プロジェクト: すべてのイベントタイプを1つのハンドラ関数に統合することを開発しました。条件付き型で、それぞれのイベントタイプが分配を通じてハンドラに渡されると期待していましたが、明示的な使用なしに実装したため、不適切に処理され、引数の間違った型(各タイプのための単独呼び出しの代わりにユニオン)が発生しました。
ストーリー
プロジェクト: 自分のユーティリティ型(Exclude、Extractなど)を作成する際、タプルや配列に対して分配が行われないことを忘れていました。その結果、Exclude型は配列に対して機能しませんでした(例:型
Exclude<["a"|"b"], "b">は "b" を削除しませんでした)。