📘

OmitとPickの使い分け、迷うことあるよね。

に公開

はじめに

最近、TypeScriptの型定義を見直していて気づいたことがあります。Omit と Pick、どっちを使うべきか迷う場面って意外と多いんですよね。

「どっちでも書けるけど、どっちが良いの?」という疑問に答えます。


結論:除外するプロパティが少ない方を使う

type User = {
  id: number
  name: string
  email: string
  password: string
  createdAt: Date
  updatedAt: Date
}

// パターン1: Pick(必要なものだけ選ぶ)
type UserResponse = Pick<User, 'id' | 'name' | 'email'>

// パターン2: Omit(不要なものを除外)
type UserResponse = Omit<User, 'password' | 'createdAt' | 'updatedAt'>

どちらも同じ結果になりますが、除外する項目が少ない方が読みやすいです。


判断基準:元の型に対する「割合」

ケース1: 大部分を使う → Omit

type Product = {
  id: number
  name: string
  price: number
  description: string
  stock: number
  categoryId: number
  createdAt: Date
  updatedAt: Date
}

// ❌ Pick だと長い
type CreateProductInput = Pick<Product, 'name' | 'price' | 'description' | 'stock' | 'categoryId'>

// ✅ Omit の方が短い
type CreateProductInput = Omit<Product, 'id' | 'createdAt' | 'updatedAt'>

8個中3個除外 → Omit が適切


ケース2: 一部だけ使う → Pick

type Article = {
  id: number
  title: string
  body: string
  authorId: number
  categoryId: number
  tags: string[]
  viewCount: number
  likeCount: number
  publishedAt: Date
  createdAt: Date
  updatedAt: Date
}

// ❌ Omit だと長い
type ArticleCard = Omit<Article, 'body' | 'authorId' | 'categoryId' | 'tags' | 'viewCount' | 'likeCount' | 'publishedAt' | 'createdAt' | 'updatedAt'>

// ✅ Pick の方が短い
type ArticleCard = Pick<Article, 'id' | 'title'>

11個中2個使用 → Pick が適切


実務でよくあるパターン

パターン1: API レスポンス型(Omit)

type User = {
  id: number
  name: string
  email: string
  password: string  // ← 外部に出してはいけない
  salt: string      // ← 外部に出してはいけない
}

// ✅ セキュリティ的に除外すべきものを明示
type UserResponse = Omit<User, 'password' | 'salt'>

意図: 「password と salt は外に出さない」を明示


パターン2: フォーム入力型(Pick)

type User = {
  id: number
  name: string
  email: string
  role: 'admin' | 'user'
  createdAt: Date
  updatedAt: Date
}

// ✅ ユーザーが入力できる項目だけを明示
type UserFormInput = Pick<User, 'name' | 'email'>

意図: 「name と email だけ入力できる」を明示


パターン3: 更新用型(両方使う)

type Product = {
  id: number
  name: string
  price: number
  createdAt: Date
  updatedAt: Date
}

// id は必須、タイムスタンプは除外、他は optional
type UpdateProductInput = Partial<Omit<Product, 'createdAt' | 'updatedAt'>> & Pick<Product, 'id'>

// 結果: { id: number; name?: string; price?: number }

実務での頻出パターン:PATCH リクエストの型定義


重要:拡張性の違い

実はOmit の方が拡張性が高いです。

元の型にプロパティが追加された時の挙動

// 最初の User 型
type User = {
  id: number
  name: string
  email: string
}

// ❌ Pick: 新しいプロパティは自動で含まれない
type UserResponse = Pick<User, 'id' | 'name' | 'email'>

// ✅ Omit: 新しいプロパティは自動で含まれる
type UserResponse = Omit<User, 'password'>

後から User に age: number を追加したとします:

type User = {
  id: number
  name: string
  email: string
  age: number  // ← 追加
}

// Pick: age は含まれない(明示的に追加が必要)
type UserResponse = Pick<User, 'id' | 'name' | 'email'>
// → { id: number; name: string; email: string }

// Omit: age は自動で含まれる
type UserResponse = Omit<User, 'password'>
// → { id: number; name: string; email: string; age: number }

実務での判断

// ケース1: セキュリティで除外する項目が決まっている → Omit
type UserResponse = Omit<User, 'password' | 'salt'>
// User に新しいプロパティが増えても、password/salt 以外は全部レスポンスに含まれる

// ケース2: フォームで入力できる項目が決まっている → Pick
type UserFormInput = Pick<User, 'name' | 'email'>
// User に新しいプロパティが増えても、フォームでは name/email だけ入力可能

拡張性を考えると Omit の方が有利ですが、意図的に制限したい場合は Pickを使います。


迷った時の判断フロー

1. 拡張性を考える(最重要)

   → 将来プロパティが増えそう & 自動で含めたい:Omit
   → 項目を厳密に制限したい:Pick

2. 元の型に対して「使う項目」は何割?

   → 5割以上:Omit(不要なものを除外)
   → 5割未満:Pick(必要なものを選択)

3. 意図を明示したい場合

   → セキュリティ:Omit(「これは出さない」を明示)
   → 入力制限:Pick(「これだけ許可」を明示)

4. どっちでも同じなら

   → 短い方を選ぶ

よくある間違い

間違い1: 無理に Omit を使う

type Config = {
  apiUrl: string
  timeout: number
  retryCount: number
  debug: boolean
  logLevel: 'info' | 'warn' | 'error'
}

// ❌ 長い
type MinimalConfig = Omit<Config, 'timeout' | 'retryCount' | 'debug' | 'logLevel'>

// ✅ 短い
type MinimalConfig = Pick<Config, 'apiUrl'>

間違い2: 型安全性を失う

type User = {
  id: number
  name: string
  email: string
  age: number
}

// ❌ age を追加したら UserResponse に漏れる
type UserResponse = Omit<User, 'password'>  // password は元々ない

// ✅ 意図が明確
type UserResponse = Pick<User, 'id' | 'name' | 'email'>

Omit は「元の型にあるもの」しか除外できないので注意。


まとめ

Omit Pick
使い時 大部分を使う時 一部だけ使う時
意図 「これは出さない」 「これだけ許可」
実務例 API レスポンス(秘匿情報除外) フォーム入力(入力項目限定)

迷ったら「短い方」を選ぶでOKです👍


おまけ: 組み合わせパターン

実務でよく使う組み合わせ:

// パターン1: Omit + Partial(更新用)
type UpdateInput = Partial<Omit<User, 'id' | 'createdAt'>>

// パターン2: Pick + Required(必須化)
type LoginInput = Required<Pick<User, 'email' | 'password'>>

// パターン3: Omit + Pick(複雑な条件)
type FormData = Partial<Omit<User, 'createdAt' | 'updatedAt'>> & Pick<User, 'id'>

慣れてきたら、こういう組み合わせもサクッと書けるようになります。


Discussion