はじめに
マッピング型(Mapped Types) は、既存のオブジェクト型のキーをイテレーションして新しい型を生成する機能です。Array.prototype.map() の型レベル版といえます。{ [K in keyof T]: T[K] } という構文で、各プロパティに変換を適用します。
基本のマッピング型
最もシンプルなマッピング型は、既存の型をそのままクローンします:
type Clone<T> = { [K in keyof T]: T[K] };
interface User {
name: string;
age: number;
}
type UserClone = Clone<User>;
// { name: string; age: number }
修飾子の追加
マッピング型では三つの修飾子を適用できます:readonly、?(オプショナル)、-(除去):
// 全プロパティを読み取り専用に
type MyReadonly<T> = { readonly [K in keyof T]: T[K] };
// 全プロパティをオプショナルに
type MyPartial<T> = { [K in keyof T]?: T[K] };
// readonlyを解除(-修飾子)
type MyMutable<T> = { -readonly [K in keyof T]: T[K] };
// オプショナルを解除
type MyRequired<T> = { [K in keyof T]-?: T[K] };
これらは Readonly<T>、Partial<T>、Required<T> の実装そのものです。
as句によるキーのフィルタリングとリマッピング
TypeScript 4.1で導入された as句 を使うと、キーのフィルタリングやリネームが可能です:
// 文字列型のプロパティだけを抽出
type StringKeys<T> = {
[K in keyof T as T[K] extends string ? K : never]: T[K];
};
interface User {
name: string;
age: number;
email: string;
}
type OnlyStrings = StringKeys<User>;
// { name: string; email: string }
テンプレートリテラル型との組み合わせ
キー名にテンプレートリテラル型を適用して変換します:
// 全キーにプレフィックスを追加
type WithPrefix<T, P extends string> = {
[K in keyof T as `${P}_${K & string}`]: T[K];
};
interface User {
name: string;
age: number;
}
type Prefixed = WithPrefix<User, 'user'>;
// { user_name: string; user_age: number }
Getterパターンへの変換:
type Getters<T> = {
[K in keyof T as `get${Capitalize<K & string>}`]: () => T[K];
};
type UserGetters = Getters<{ name: string; age: number }>;
// { getName: () => string; getAge: () => number }
Pick と Omit の実装
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
type MyOmit<T, K extends keyof any> = {
[P in keyof T as P extends K ? never : P]: T[P];
};
実践的なパターン
Deep Partial(再帰的マッピング型)
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
Nullable 変換
type Nullable<T> = {
[K in keyof T]: T[K] | null;
};
キーのリネーム
type RenameKeys<T, M extends Record<string, string>> = {
[K in keyof T as K extends keyof M ? M[K] : K]: T[K];
};
まとめ
マッピング型はTypeScriptの型変換機能の中核です。基本的な修飾子からas句によるキーリマッピング、テンプレートリテラルとの組み合わせまで、柔軟な型変換を可能にします。条件付き型と組み合わせれば、真のコンパイル時メタプログラミングが実現できます。
