TypeScript Pick, Omit, Partial ユーティリティ型の実務組み合わせパターン

問題

DBモデルの型は一つですが、APIリクエストごとに必要なフィールドが異なります。作成時はidを除いてすべて必須、更新時はidが必須で残りは任意。毎回新しいインターフェースを定義すると、型が際限なく増えてしまいます。

解決方法

ユーティリティ型を組み合わせることで、既存の型から派生させることができます。

interface User {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user';
  createdAt: Date;
}

// 作成リクエスト: id, createdAtを除外
type CreateUserDto = Omit<User, 'id' | 'createdAt'>;

// 更新リクエスト: id必須、残りは任意
type UpdateUserDto = Pick<User, 'id'> & Partial<Omit<User, 'id'>>;

// 一覧レスポンス: 必要なフィールドだけ
type UserListItem = Pick<User, 'id' | 'name' | 'email'>;

よく使うパターンはジェネリック型にしておくと便利です。

// 更新DTO: Kフィールドは必須、残りは任意
type UpdateDto<T, K extends keyof T> = Pick<T, K> & Partial<Omit<T, K>>;

type UpdateUserDto = UpdateDto<User, 'id'>;
type UpdatePostDto = UpdateDto<Post, 'id' | 'slug'>;

ポイント

  • Omit<T, K>: 特定フィールドを除外(作成DTOに最適)
  • Pick<T, K>: 特定フィールドだけ選択(一覧・要約型に最適)
  • Partial<T>: すべてのフィールドを任意に(更新DTOに最適)
  • 組み合わせることで、新しいインターフェースなしに既存の型から派生できます
  • よく使うパターンはジェネリック型として抽出しておくと再利用性が高まります