【TypeScript】mapped typesで型を自動生成 - 詳細解説
概要
TypeScriptのmapped typesは、既存の型を基に新しい型を自動生成する機能で、型の再利用性と保守性を向上させる強力なツールです。例えば、オプションの型、読み取り専用の型、必須の型など、プロパティに対して条件を付けた型を簡単に作成できます。本記事では、mapped typesの基本から応用例までを詳しく解説し、効率的な型定義の方法を学びます。
mapped typesとは?
mapped typesは、既存の型に対して修飾や制限を加えた新しい型を動的に生成するためのTypeScriptの機能です。{ [P in K]: T }のようなシンタックスを用いて、オブジェクト型のプロパティを一括で操作できます。例えば、あるオブジェクト型のプロパティすべてをオプションにしたり、読み取り専用にしたりといった操作が可能です。
mapped typesの基本構文
基本的なmapped typesの構文は以下の通りです。
type MappedType<T> = {
[P in keyof T]: T[P];
};
ここで、T型の各プロパティPが新しい型MappedTypeとして定義されます。keyofは、オブジェクト型のすべてのプロパティのキーを取得するユーティリティです。
mapped typesの代表例
Partial - 部分型の生成
Partialは、すべてのプロパティをオプションにした型を生成します。例えば、オプションのプロパティが増えるフォームのデータや、APIのレスポンス型などに便利です。
type User = {
id: number;
name: string;
email: string;
};
type PartialUser = Partial<User>; // すべてのプロパティがオプションになる
const user1: PartialUser = {
name: "Alice"
}; // 問題なし
Readonly - 読み取り専用の型
Readonlyは、すべてのプロパティを読み取り専用にする型を生成します。この型は、データが誤って変更されないように保護したいときに役立ちます。
type ReadonlyUser = Readonly<User>;
const user2: ReadonlyUser = {
id: 1,
name: "Bob",
email: "bob@example.com"
};
// user2.name = "Alice"; // エラー: 読み取り専用プロパティ
Required - 必須プロパティの指定
Requiredは、すべてのプロパティを必須にした型を生成します。通常オプションのプロパティを持つ型を確実にすべて設定する必要がある場合に使用します。
type UserWithOptional = {
id: number;
name?: string;
};
type CompleteUser = Required<UserWithOptional>;
const user3: CompleteUser = {
id: 2,
name: "Charlie"
}; // nameプロパティが必須になる
Record - キーの一覧に対する型を一括設定
Recordは、指定したキーの一覧に対して同じ型を一括で割り当てる型です。例えば、オブジェクトのキーに対してすべて同じ型の値を持たせたい場合に使います。
type Role = "admin" | "user" | "guest";
type Permissions = Record<Role, string[]>;
const permissions: Permissions = {
admin: ["read", "write", "delete"],
user: ["read", "write"],
guest: ["read"]
};
カスタムmapped typesの作成
mapped typesは、カスタムの型を柔軟に作成するために用いることもできます。たとえば、すべてのプロパティをオプションにし、同時にプロパティの型を変更するカスタム型を作成できます。
Nullable - プロパティをnull可能にする型
以下の例では、すべてのプロパティをnull許容にするNullable型を作成しています。
type Nullable<T> = {
[P in keyof T]: T[P] | null;
};
type NullableUser = Nullable<User>;
const user4: NullableUser = {
id: null,
name: "Dave",
email: null
};
Mutable - Readonlyプロパティを変更可能に
TypeScriptのReadonly型で設定したプロパティを再び変更可能にするMutable型を定義することも可能です。
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
type MutableUser = Mutable<ReadonlyUser>;
const user5: MutableUser = {
id: 1,
name: "Eve",
email: "eve@example.com"
};
user5.name = "Alice"; // 問題なし
-readonlyとすることで、プロパティの読み取り専用修飾を解除し、変更可能なプロパティに戻しています。
条件付き型と組み合わせた応用
mapped typesは条件付き型(conditional types)と組み合わせることで、さらに高度な型操作が可能です。例えば、never型を使用して特定のプロパティを除外する型などを作成できます。
PickとExcludeで特定のプロパティを取り出す
PickとExcludeを使うことで、特定のプロパティのみを抽出したり除外したりすることができます。
type PickNameAndEmail = Pick<User, "name" | "email">;
const user6: PickNameAndEmail = {
name: "Frank",
email: "frank@example.com"
};
type ExcludeEmail = Exclude<keyof User, "email">; // "id" | "name" のみ
Pickは指定したプロパティだけを含む新しい型を生成し、Excludeは指定した型を除外したユニオン型を生成します。
DeepReadonly - ネストしたプロパティも読み取り専用にする
ネストされたオブジェクトのプロパティも含めてすべて読み取り専用にするには、再帰的なmapped typesを使います。
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
type ComplexUser = {
id: number;
profile: {
name: string;
age: number;
};
};
type ReadonlyComplexUser = DeepReadonly<ComplexUser>;
const complexUser: ReadonlyComplexUser = {
id: 1,
profile: {
name: "Grace",
age: 29
}
};
// complexUser.profile.name = "Alice"; // エラー
この例では、DeepReadonly型を使用してネストされたプロパティもすべて読み取り専用にしています。再帰的な条件でobject型を判定し、オブジェクトであれば再帰的にDeepReadonlyを適用しています。
まとめ
TypeScriptのmapped typesは、型の柔
軟な操作や再利用性を高めるために欠かせない機能です。既存の型に対してプロパティを動的に変更し、PartialやReadonlyといったユーティリティ型からカスタムmapped typesまで幅広く活用することができます。mapped typesと条件付き型を組み合わせて複雑な型操作を実現し、プロジェクトのメンテナンス性を向上させましょう。
Recommend
2024-11-10
【TypeScript】非同期処理と例外処理 - 型安全な実装
2024-11-10
【TypeScript】Astroでの最新Web開発スタック解説 - 静的サイト生成と型安全な開発
2024-11-10
【TypeScript】APIクライアントの型安全な実装方法 - 型安全性を高めるためのベストプラクティス
2024-11-10
【TypeScript】AWS CDKでのServerless開発実践 - 基本からデプロイまで
2024-11-10
【TypeScript】ビルドツールごとの最適な設定方法 - 効率的な開発環境を構築
2024-11-10
【TypeScript】ビルダーパターンの型定義ガイド - 型安全なオブジェクト生成
2024-11-10
【TypeScript】コマンドパターンの型安全な実装 - 柔軟な操作管理と拡張性の確保
2024-11-10
【TypeScript】条件付き型の活用 - 高度な型プログラミング
2024-11-10
【TypeScript】デコレーターパターンの実装ガイド - 柔軟な機能拡張の実現
2024-11-10
【TypeScript】ESLint & Prettier - コード品質維持ガイド
2024-11-10
【TypeScript】デコレータ実践 - メタプログラミング入門
2024-11-10
【TypeScript】tsconfig.json完全ガイド - 最適な設定解説