分配条件型
条件型がユニオンに対してどのように分配されるかを制御します。
「分配条件型」はCoddyKit上の無料TypeScript Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはTypeScript Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 TypeScript Academyコースには全4レッスンが含まれています。
驚くべき動作
条件型には、特別なルールが1つあります。チェック対象の型が裸の型パラメーターで、そこにユニオンを渡すと、条件型は各メンバーに個別に分配され、その結果がユニオンになります。
これは Exclude、Extract、その他多くのユーティリティ型の基盤です。
type ToArray<T> = T extends unknown ? T[] : never;
type A = ToArray<string | number>;
// string[] | number[] (NOT (string | number)[])「naked」の意味
「naked」とは、型パラメーターが extends の左側に、別の型でラップされず単独で現れることを意味します。分配が起きるのは、裸のパラメーターの場合だけです。
type Naked<T> = T extends string ? "y" : "n";
// T is naked -> distributes over unions分配をステップごとに見る
ToArray<string | number> では、コンパイラーは各メンバーを評価します。
ToArray<string>= string[]ToArray<number>= number[]
その後、それらをユニオンにします:string[] | number[]。
type R = ToArray<boolean>;
// boolean is true | false, so:
// true[] | false[]ユニオンをフィルタリングする
分配によって、フィルタリングが簡単になります。不要なメンバーを never に変換すると、never はユニオンから消え、残したメンバーだけが残ります。
type Strings<T> = T extends string ? T : never;
type A = Strings<string | number | boolean>; // stringユニオンでは never が消える
重要なポイントは、X | never が X に簡約されることです。そのため、分配された分岐が never を生成すると、そのメンバーは最終的なユニオンから実質的に取り除かれます。
type A = string | never; // string
type B = "a" | never | "b"; // "a" | "b"分配を無効にする
ユニオン全体を1つの単位として比較する場合など、分配を望まないことがあります。その場合は、両辺を1要素のタプルでラップします:[T] extends [U]。これで T は裸ではなくなるため、分配が無効になります。
type IsNever<T> = [T] extends [never] ? true : false;
type A = IsNever<never>; // true
type B = IsNever<string>; // falseラップで機能する理由
左側に [T] を置くと、チェック対象の型は裸のパラメーターではなくタプルになります。特別な分配ルールが適用されなくなり、ユニオン全体が1つの型としてテストされます。
type AllStrings<T> = [T] extends [string] ? true : false;
type A = AllStrings<"a" | "b">; // true
type B = AllStrings<"a" | number>; // false分配ありと分配なし
2つの形式を直接比較してみましょう。裸の形式は各メンバーをチェックし、ラップした形式はユニオンを1つの型としてチェックします。
type Distributed<T> = T extends string ? true : false;
type Wrapped<T> = [T] extends [string] ? true : false;
type A = Distributed<string | number>; // boolean (true | false)
type B = Wrapped<string | number>; // falseExclude の内部
組み込みの Exclude<T, U> は、U に代入可能なメンバーを T から取り除きます。これは、一致するメンバーを never に変換する分配条件型にすぎません。
type MyExclude<T, U> = T extends U ? never : T;
type A = MyExclude<"a" | "b" | "c", "b">; // "a" | "c"Extract の内部
Extract<T, U> はその反対です。U に代入可能なメンバーだけを残します。同じ分配を使いますが、分岐の役割が逆です。
type MyExtract<T, U> = T extends U ? T : never;
type A = MyExtract<"a" | "b" | "c", "a" | "c">; // "a" | "c"実践的な威力
分配を使うと、1つの式でユニオンのすべてのメンバーを変換できます。各メンバーの配列を作ったり、すべての文字列にプレフィックスを付けたり、形状でフィルタリングしたりできます。ユニオン全体をチェックする [T] extends [U] と組み合わせることで、分配を正確に発生させるタイミングを制御できます。
表記: 実際の TypeScript では、テンプレートリテラル型を、ドル記号と中かっこの穴を含むバッククォートで区切られた文字列として記述します。これらのスニペットでは、そのパターンを Tpl<...> として示し、各部分を順番に並べています。たとえば、リテラルのプレフィックスに続いて Rest に一致するバッククォートテンプレートは、Tpl<'prefix', infer Rest> として表します。
type Prefix<T extends string> = T extends unknown ? Tpl<'id_', T> : never;
// Tpl<'id_', T> is the template literal type joining 'id_' with each T
type A = Prefix<'a' | 'b'>; // 'id_a' | 'id_b'理解度チェック
分配条件型について、理解度を確認しましょう。
まとめ
分配条件型は、ユニオン用ユーティリティの原動力です。
- 裸の
T extends U ?は、各ユニオンメンバーに対して分配されます。 neverを返す分岐によって、メンバーをフィルタリングできます。[T] extends [U]は、ユニオン全体のチェック時に分配を無効にします。ExcludeとExtractは、小さな分配条件型です。
次のコース22では、型システムで算術を扱います。
よくある質問
「分配条件型」レッスンは無料ですか?
はい。「分配条件型」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、TypeScript Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 TypeScript Academyコースには全4レッスンが含まれています。
「分配条件型」で何を学びますか?
条件型がユニオンに対してどのように分配されるかを制御します。 ブラウザで直接実行するハンズオンコードでTypeScript Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
TypeScript Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのTypeScript Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「分配条件型」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このTypeScript Academyレッスンでコードを書いて実行できますか?
はい。すべてのTypeScript Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。