これらは TypeScript の 型レベルプログラミング のためのツールであり、既存の型から新しい型を計算します。
mapped types — 各プロパティを変換する
mapped type は型のキーを反復処理し、それぞれを変換します。
ts
<T> = { [K keyof T]: T[K] };
<T> = { [K keyof T]?: T[K] };
{ : ; : ; }
= <>;
これらは TypeScript の 型レベルプログラミング のためのツールであり、既存の型から新しい型を計算します。
mapped type は型のキーを反復処理し、それぞれを変換します。
<T> = { [K keyof T]: T[K] };
<T> = { [K keyof T]?: T[K] };
{ : ; : ; }
= <>;
[K in keyof T] は各キー K をループします。T[K] はそのキーの値の型です。これが Partial、Readonly、Required が実装されている方法です。キーを再マッピングしたり、修飾子を追加したりすることもできます(-readonly、-? はそれらを取り除きます)。
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<string>; // "yes"
type B = IsString<number>; // "no"
T extends U ? X : Y は型レベルの if/else です。infer を使うと、条件の中で型を 抽出 できます。
type ElementOf<T> = T extends (infer U)[] ? U : never;
type E = ElementOf<string[]>; // string
// Make only the function-valued properties optional
type PartialMethods<T> = {
[K in keyof T]: T[K] extends Function ? T[K] | undefined : T[K];
};
mapped types は conditional の中で union に対して 分配(distribute) もするため、強力な変換が可能になります。
mapped types と conditional types により、ライブラリは正確な型の関係を表現できます。これらはユーティリティ型を実装し、フォーム/バリデーションライブラリ、ORM のクエリビルダー、そしてレスポンスの shape を推論する API クライアントを支えています。
これらは高度なものですが、これを理解することで TypeScript の型システムが なぜ これほど表現力豊かでいられるのかが分かり、バリエーションを手書きする代わりに再利用可能な型変換を構築できるようになります。