TypeScript ユーティリティ型

ユーティリティ型(Utility Types)は、TypeScript に組み込まれた一連の高度な型です。

これらは開発者が型を迅速に作成・変換し、コードの再利用性と型安全性を高めるのに役立ちます。

ユーティリティ型は本質的にジェネリック型であり、マップ型と条件型によって実装されています。


背景 タイトル TypeScript ユーティリティ型 プリミティブ型 プリミティブ型 interface User { id: number; name: string; email: string; } 矢印 ユーティリティ型 ユーティリティ型 Partial<T> - すべてオプション Required<T> - すべて必須 Readonly<T> - すべて読み取り専用 Pick<T,K> - プロパティを選択 Omit<T,K> - プロパティを除外 矢印 結果 結果型 type Result = { id?: number; name?: string; email?: string; } 下半分 よく使うユーティリティ型 1行目 Partial<T> すべてのプロパティがオプション { a?: T } Required<T> すべてのプロパティが必須 { -? } Readonly<T> すべてのプロパティが読み取り専用 { readonly } Pick<T,K> 指定したプロパティを選択 { pick } 2行目(修正の要点) Record<K,T> オブジェクト型を構築 Omit<T,K> 指定したプロパティを除外 矢印の定義

なぜユーティリティ型が必要か

実際の TypeScript 開発では、既存の型に基づいて新しい型を作成する必要がよくあります。

これらの型を手動で作成するのは手間がかかるだけでなく、エラーも発生しやすくなります。

ユーティリティ型は、型を変換・作成するための宣言的な方法を提供し、開発効率を大幅に向上させます。

概念の説明:ユーティリティ型は、TypeScript であらかじめ定義された一連のジェネリック型です。マップ型と条件型を使用して、型の変換と生成を実現します。


Partial<T> - オプションのプロパティ

Partial は、型 T のすべてのプロパティをオプションにします。

これは、部分更新オブジェクトを作成したり、フォームデータを処理したりする場合に非常に便利です。

例

// 必須プロパティを含むユーザーインターフェースを定義
interface User {
    // ユーザーID
    id: number;
    // ユーザー名
    name: string;
    // ユーザーメールアドレス
    email: string;
}

// Partial: すべてのプロパティをオプションにする
// 変換後の型はすべてのプロパティがオプションになる
type PartialUser = Partial<User>;

// PartialUser 型を使用
// 一部のプロパティのみを指定でき、すべてを指定する必要はない
var user: PartialUser = { name: "Alice" };

console.log("部分ユーザー: " + JSON.stringify(user));

実行結果:

部分用户: {"name":"Alice"}

適用シーン:Partial は、オブジェクトデータを更新するときによく使われます。例:ユーザーの一部の情報だけを更新する場合、完全なユーザーオブジェクトを渡す必要はありません。


Required<T> - 必須プロパティ

Required は Partial とは逆に、すべてのオプションのプロパティを必須にします。

オブジェクトがすべてのプロパティを含むことを保証する必要がある場合に使用します。

例

// プロパティがすべてオプションの設定インターフェースを定義
interface Config {
    // サーバーアドレス
    host?: string;
    // ポート番号
    port?: number;
}

// Required: すべてのオプションのプロパティを必須にする
// 変換後の型はすべてのプロパティが必須になる
type RequiredConfig = Required<Config>;

// RequiredConfig 型を使用
// すべてのプロパティを指定する必要がある
var config: RequiredConfig = { host: "localhost", port: 8080 };

console.log("設定: " + JSON.stringify(config));

実行結果:

配置: {"host":"localhost","port":8080}

説明:Required はオプションのプロパティ(?)を削除するだけでなく、readonly 修飾子も削除します。


Readonly<T> - 読み取り専用プロパティ

Readonly はすべてのプロパティを読み取り専用にします。

作成後に変更が許可されないオブジェクトに非常に便利です。

例

// ユーザーインターフェースを定義
interface User {
    // ユーザー名
    name: string;
    // ユーザーの年齢
    age: number;
}

// Readonly: すべてのプロパティを読み取り専用にする
// 変換後の型はすべてのプロパティが変更不可
type ReadonlyUser = Readonly<User>;

// 読み取り専用のユーザーオブジェクトを作成
var user: ReadonlyUser = { name: "Alice", age: 25 };

// 読み取り専用プロパティを変更しようとするとエラーになる
// user.name = "Bob"; // エラー:読み取り専用プロパティは変更できない

console.log("読み取り専用ユーザー: " + JSON.stringify(user));

適用シーン:Readonly は、設定オブジェクトや列挙値のマッピングなど、変更されたくないデータを定義するときによく使われます。


Pick<T, K> - プロパティを選択

Pick は、型 T から指定したプロパティ K を選択して新しい型を構成します。

ある型の一部のプロパティだけが必要な場合に使用します。

例

// 完全なユーザーインターフェースを定義
interface User {
    // ユーザーID
    id: number;
    // ユーザー名
    name: string;
    // ユーザーメールアドレス
    email: string;
    // ユーザーパスワード
    password: string;
}

// Pick: 指定したプロパティを選択して新しい型を構成
// User から id と name プロパティを選択
type UserBasicInfo = Pick<User, "id" | "name">;

// 選択後の型を使用
var user: UserBasicInfo = { id: 1, name: "Alice" };

console.log("ユーザー基本情報: " + JSON.stringify(user));

実行結果:

用户基本信息: {"id":1,"name":"Alice"}

比較:Pick を Partial と組み合わせて使用すると、一部のオプションのプロパティのみを含む型を作成できます。


Omit<T, K> - プロパティを除外

Omit は、型 T から指定したプロパティ K を除外し、残りのプロパティで構成される新しい型を返します。

Pick とは逆に、不要なプロパティを削除するために使用します。

例

// 完全なユーザーインターフェースを定義
interface User {
    // ユーザーID
    id: number;
    // ユーザー名
    name: string;
    // ユーザーメールアドレス
    email: string;
    // ユーザーパスワード
    password: string;
}

// Omit: 指定したプロパティを除外
// User から password プロパティを除外
type UserWithoutPassword = Omit<User, "password">;

// 除外後の型を使用
var user: UserWithoutPassword = { id: 1, name: "Alice", email: "[email protected]" };

console.log("パスワードなしユーザー: " + JSON.stringify(user));

実行結果:

无密码用户: {"id":1,"name":"Alice","email":"[email protected]"}

ヒント:Omit は Pick の逆の操作です。少数のプロパティを除外する必要がある場合は Omit を、少数のプロパティを選択する必要がある場合は Pick を使用します。


Record<K, T> - オブジェクト型を構築

Record は、キーの型が K、値の型が T であるオブジェクト型を構築します。

キーと値のペアのマッピングや辞書型などを作成するときによく使われます。

例

// ロール型を定義
type Role = "admin" | "user" | "guest";

// Record: オブジェクト型を構築
// キーは Role 型、値は文字列配列型
type RolePermissions = Record<Role, string[]>;

// Record を使用して権限マッピングを作成
var permissions: RolePermissions = {
    // 管理者はすべての権限を持つ
    admin: ["read", "write", "delete"],
    // 一般ユーザーは読み書き権限を持つ
    user: ["read", "write"],
    // ゲストは読み取り権限のみ
    guest: ["read"]
};

console.log("管理者権限: " + permissions.admin);
console.log("ゲスト権限: " + permissions.guest);

実行結果:

管理员权限: read,write,delete
访客权限: read

適用シーン:Record は、キーに基づいて値をすばやく検索する必要がある設定マッピング、状態マッピング、権限マッピングなどのシーンでよく使われます。


Exclude<T, U> - 型を除外

Exclude は、型 T から型 U に代入可能な型を除外します。

主にユニオン型で使用され、特定の型メンバーを除外します。

例

// ユニオン型を定義し、a、b、c、d を含む
type T = "a" | "b" | "c" | "d";

// Exclude:T から指定した型を除外する
// "a"、"b"、"c" を除外し、"d" のみを残す
type NonABC = Exclude<T, "a" | "b" | "c">;

// 除外後の型を使用し、"d" のみ代入できる
var value: NonABC = "d";

console.log("値: " + value);

実行結果:

值: d

説明:Exclude の原理は、T 内のある型が U に代入可能な場合、T からそれを除去するというものです。


Extract<T, U> - 型を抽出

Extract は Exclude とは逆で、型 T から型 U に代入可能な型を抽出します。

ユニオン型内の特定のメンバーを絞り込むために使用します。

例

// 文字列と数値を含む混合ユニオン型を定義する
type T = "a" | "b" | "c" | 1 | 2 | 3;

// Extract:T から指定した型を抽出する
// すべての文字列型を抽出:"a"、"b"、"c"
type Letters = Extract<T, string>;

// 抽出後の型を使用する
var letter: Letters = "a";

console.log("文字: " + letter);

実行結果:

字母: a

対比:Extract と Exclude は相補的です。Extract(T, U) は Exclude(T, Exclude<T, U>) と同等です。


NonNullable<T> - null/undefined を除外

NonNullable は型 T から null と undefined を除外します。

型に空値が含まれないようにする場合に使用します。

例

// 文字列、null、undefined、数値を含む混合型を定義する
type T = string | null | undefined | number;

// NonNullable:null と undefined を除外する
// 変換後は string と number のみ残る
type NotNull = NonNullable<T>;

// 非空型を使用する
var value: NotNull = "hello";
value = 42;

// null を代入しようとするとエラーになる
// value = null; // エラー:null を代入できない

console.log("値: " + value);

説明:NonNullable<T> は Exclude<T, null | undefined> と同等です。


ReturnType<T> - 戻り値の型を取得

ReturnType は関数型 T の戻り値の型を取得します。

既存の関数から戻り値の型を抽出する際によく使用されます。

例

// ユーザーを取得する関数を定義する
function getUser() {
    return { name: "Alice", age: 25 };
}

// 設定を取得する関数を定義する
function getConfig() {
    return { host: "localhost", port: 8080 };
}

// ReturnType:関数の戻り値の型を取得する
// getUser 関数の戻り値の型を抽出する
type UserType = ReturnType<typeof getUser>;
// getConfig 関数の戻り値の型を抽出する
type ConfigType = ReturnType<typeof getConfig>;

// 抽出した戻り値の型を使用してオブジェクトを作成する
var user: UserType = { name: "Bob", age: 30 };
var config: ConfigType = { host: "example.com", port: 3000 };

console.log("ユーザー: " + JSON.stringify(user));
console.log("設定: " + JSON.stringify(config));

実行結果:

ユーザー: {"name":"Bob","age":30}
配置: {"host":"example.com","port":3000}

ヒント:ReturnType<T> の T は関数型である必要があります。typeof を使用して関数の型を取得できます。


注意事項

  • ユーティリティ型はすべてジェネリックです:使用時は具体的な型パラメータを渡す必要があります
  • 読み取り専用とオプション:ユーティリティ型は組み合わせて使用できます。例:Partial<Readonly<T>>
  • 組み込み型:これらのユーティリティ型はすべて TypeScript に組み込まれており、インストールは不要です
  • カスタムユーティリティ型:マップ型と条件型に基づいてカスタムユーティリティ型を作成できます

発展:組み込みのユーティリティ型で要件を満たせない場合は、TypeScript のソースコードを参考にして独自のカスタムユーティリティ型を実装できます。


まとめ

TypeScript のユーティリティ型は型システムの重要な構成要素です。

  • Partial<T>:すべてのプロパティをオプションにする
  • Required<T>:すべてのプロパティを必須にする
  • Readonly<T>:すべてのプロパティを読み取り専用にする
  • Pick<T,K>:指定したプロパティを選択する
  • Omit<T,K>:指定したプロパティを除外する
  • Record<K,T>:オブジェクト型を構築する
  • Exclude/Extract:型のフィルタリング
  • NonNullable:null と undefined を除外する
  • ReturnType:関数の戻り値の型を取得する

ベストプラクティス:ユーティリティ型を活用することで、コードの型安全性が向上し、冗長な型定義を減らし、コードの保守性を高めることができます。


その他の拡張