📚

TypeScript Utility Types【基本編】

に公開

はじめに

この記事では、TypeScript で最も頻繁に使用される基本的な Utility Types を実例を交えて詳しく解説していきます。

基本の Utility Types

Partial<T> - プロパティを全てオプショナルに

Partial<T>は、型Tのすべてのプロパティをオプショナル(?付き)にします。

interface User {
  id: number;
  name: string;
  email: string;
  age: number;
}

// すべてのプロパティがオプショナルになる
type PartialUser = Partial<User>;
// {
//   id?: number;
//   name?: string;
//   email?: string;
//   age?: number;
// }

// 使用例:ユーザー情報の更新
function updateUser(id: number, updates: Partial<User>) {
  // 一部のプロパティのみ更新可能
}

updateUser(1, { name: "新しい名前" }); // ✅ OK
updateUser(1, { age: 25, email: "new@example.com" }); // ✅ OK

Required<T> - プロパティを全て必須に

Required<T>は、Partial<T>の逆で、すべてのプロパティを必須にします。

interface OptionalUser {
  id?: number;
  name?: string;
  email?: string;
}

type RequiredUser = Required<OptionalUser>;
// {
//   id: number;
//   name: string;
//   email: string;
// }

// 使用例:バリデーション後の型
function validateUser(user: OptionalUser): RequiredUser | null {
  if (user.id && user.name && user.email) {
    return user as RequiredUser;
  }
  return null;
}

Pick<T, K> - 特定のプロパティのみを抽出

Pick<T, K>は、型Tから指定したキーKのプロパティのみを抽出します。

interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// 公開情報のみを抽出
type PublicUser = Pick<User, "id" | "name" | "email">;
// {
//   id: number;
//   name: string;
//   email: string;
// }

// 使用例:APIレスポンス
function getUserPublicInfo(user: User): PublicUser {
  return {
    id: user.id,
    name: user.name,
    email: user.email,
  };
}

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

Omit<T, K>は、型Tから指定したキーKのプロパティを除外します。

interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
}

// パスワードを除外
type UserWithoutPassword = Omit<User, "password">;
// {
//   id: number;
//   name: string;
//   email: string;
//   createdAt: Date;
// }

// 複数のプロパティを除外
type CreateUserRequest = Omit<User, "id" | "createdAt">;
// {
//   name: string;
//   email: string;
//   password: string;
// }

Record<K, T> - キーと値の型を指定してオブジェクト型を作成

Record<K, T>は、キーKと値Tの型を指定してオブジェクト型を作成します。

// ユーザーの権限設定
type Permission = "read" | "write" | "delete";
type PermissionSettings = Record<Permission, boolean>;
// {
//   read: boolean;
//   write: boolean;
//   delete: boolean;
// }

const userPermissions: PermissionSettings = {
  read: true,
  write: true,
  delete: false,
};

// APIエラーコードとメッセージのマッピング
type ErrorCode = 400 | 401 | 403 | 404 | 500;
type ErrorMessages = Record<ErrorCode, string>;

const errorMessages: ErrorMessages = {
  400: "不正なリクエストです",
  401: "認証が必要です",
  403: "アクセス権限がありません",
  404: "リソースが見つかりません",
  500: "サーバーエラーが発生しました",
};

応用的な使い方

組み合わせて使用する

複数の Utility Types を組み合わせることで、より複雑な型変換が可能です。

interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  age: number;
  isActive: boolean;
}

// IDとパスワードを除外し、残りをオプショナルに
type UserUpdateRequest = Partial<Omit<User, "id" | "password">>;
// {
//   name?: string;
//   email?: string;
//   age?: number;
//   isActive?: boolean;
// }

// 特定のフィールドのみ必須、他はオプショナル
type UserRegistration = Pick<User, "name" | "email"> &
  Partial<Pick<User, "age">>;
// {
//   name: string;
//   email: string;
//   age?: number;
// }

カスタム Utility Type の作成

独自の Utility Type を作成することもできます。

// NonNullableなプロパティのみを抽出
type NonNullableKeys<T> = {
  [K in keyof T]: T[K] extends null | undefined ? never : K;
}[keyof T];

type NonNullableProperties<T> = Pick<T, NonNullableKeys<T>>;

interface MixedUser {
  id: number;
  name: string;
  email: string | null;
  age?: number;
  avatar: string | undefined;
}

type SafeUser = NonNullableProperties<MixedUser>;
// {
//   id: number;
//   name: string;
// }

実践的な使用例

API レスポンス型の管理

// ベースとなるUser型
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
  role: "admin" | "user";
  createdAt: string;
  updatedAt: string;
}

// 各APIエンドポイントのレスポンス型
type UserListResponse = Pick<User, "id" | "name" | "email" | "role">;
type UserDetailResponse = Omit<User, "password">;
type CreateUserRequest = Omit<User, "id" | "createdAt" | "updatedAt">;
type UpdateUserRequest = Partial<Pick<User, "name" | "email" | "role">>;

状態管理での活用

interface AppState {
  user: User | null;
  isLoading: boolean;
  error: string | null;
  settings: {
    theme: "light" | "dark";
    language: "ja" | "en";
  };
}

// アクションペイロードの型定義
type SetUserAction = {
  type: "SET_USER";
  payload: Pick<AppState, "user">;
};

type SetLoadingAction = {
  type: "SET_LOADING";
  payload: Pick<AppState, "isLoading">;
};

type UpdateSettingsAction = {
  type: "UPDATE_SETTINGS";
  payload: Partial<AppState["settings"]>;
};

まとめ

この基本編では、最もよく使用される 5 つの Utility Types を紹介しました:

  • Partial<T> - プロパティを全てオプショナルに
  • Required<T> - プロパティを全て必須に
  • Pick<T, K> - 特定のプロパティのみを抽出
  • Omit<T, K> - 特定のプロパティを除外
  • Record<K, T> - キーと値の型を指定してオブジェクト型を作成

これらを適切に活用することで、保守性が高く型安全なコードを書くことができます。

参考文献

https://www.typescriptlang.org/docs/handbook/utility-types.html
https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

Discussion