【TypeScript】Pickでプロパティを抽出|Omitの使い分けと型再利用
TypeScriptのPickを使うと、APIレスポンスのような大きな型から、画面表示に必要なプロパティだけを取り出して新しい型を作れます。
こうした「必要なプロパティだけを型として取り出したい」という場面は、Pickひとつで解決できます。基本構文を押さえ、Omitとの判断軸を持ち、unionでつまずく理由まで理解すれば、APIレスポンスやフォームの型を自分で整理して再利用できるようになります。
この記事は次のような方におすすめです。
- 既存の型から必要なプロパティだけを抜き出す書き方を知りたい方
- PickとOmitのどちらを使うべきか毎回迷ってしまう方
- APIレスポンスやフォームの型をきれいに再利用したい中級者の方
- 「Pickが効かない」とエラーが消えず、Pickとunion型の関係でもやもやした経験がある方
読み終えるころには、Pickで型を抽出する基本から、Omitとの使い分け、unionでの注意点、実務での型再利用パターンまでを一通り自分の手で書けるようになります。
それでは、順を追って詳しく見ていきましょう!
- 未経験で後悔したくない
【実体験】未経験からITエンジニアに転職して後悔した話|4社経験してわかった「最初の選択ミス」 - 年収が低くて不安
4年間ずっと年収260万だったエンジニアが、転職で510万になるまでの全記録
Pickとは|既存の型から必要なプロパティだけを抜き出すユーティリティ型
Pickは、既存のオブジェクト型から指定したプロパティだけを抜き出して、新しい型を作るユーティリティ型です。 元の型はそのまま残り、そこから必要なキーだけを選んだ別の型が生まれます。
たとえばユーザー情報を表す大きな型があり、画面では名前とメールアドレスだけを扱いたいとします。このとき、元の型を書き換えるのではなく、Pickで必要なプロパティだけを抜き出します。
type User = {
id: number;
name: string;
email: string;
createdAt: Date;
};
type UserCard = Pick<User, "name" | "email">;
// 結果:
// type UserCard = {
// name: string;
// email: string;
// }
UserCard にカーソルを合わせてホバーすると、name と email だけを持つ型として表示されます。元の User は変更されないため、Pickは「元の型を壊さずに、その一部を再利用する」ための道具だと考えると理解しやすいでしょう。同じ User から別の組み合わせを何度でも派生できます。
Pickの基本構文と型引数(Type と Keys)
Pick<Type, Keys> は2つの型引数を取ります。第1引数 Type には元になるオブジェクト型を、第2引数 Keys には抽出したいプロパティ名を渡します。 Keys に渡せるのは Type が持つキーだけで、複数指定するときは "name" | "email" のように文字列リテラルのunionでつなぎます(実際の抽出例は次の見出しで扱います)。
Keys に元の型に存在しないキーを渡すと、コンパイルエラーになります。これは Pick の定義そのものが、Keys を Type のキーに制約しているためです。標準ライブラリ上の実装定義は、おおよそ次のような形になっています。
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
// 定義は TypeScript のバージョンにより細部が異なる場合あり
K extends keyof T の部分が「K は T のキーの範囲に収まっていなければならない」という制約を表します。keyof T は T のキー名を集めたunion型を作る演算子で、User であれば "id" | "name" | "email" に相当します。この制約があるおかげで、存在しないキーを渡した時点でエディタが赤線を出してくれます。
Pickの基本的な使い方|単一・複数プロパティの抽出
必要なプロパティだけの型を作るには、元の型と抽出したいキーを Pick に渡すだけです。 単一プロパティなら1つのキーを、複数なら文字列リテラルのunionで並べます。
type Product = {
id: number;
name: string;
price: number;
description: string;
stock: number;
};
// 単一プロパティ
type ProductId = Pick<Product, "id">;
// type ProductId = { id: number }
// 複数プロパティ
type ProductSummary = Pick<Product, "name" | "price">;
// type ProductSummary = { name: string; price: number }
抽出して作った型は、そのまま関数の引数やオブジェクトの型注釈に使えます。たとえば商品一覧の表示には ProductSummary だけあれば十分で、description や stock を持ち回る必要がなくなります。
function renderSummary(product: ProductSummary): string {
return `${product.name}: ${product.price}円`;
}
renderSummary({ name: "ノート", price: 300 }); // OK
renderSummary({ name: "ペン", price: 100, stock: 5 }); // 例:TS2353 オブジェクトリテラルに余分なプロパティ stock があるとエラー
このように、Pickで作った型を引数に使うと「その関数が本当に必要とするプロパティ」だけを受け取る契約を表現できます。 余計なプロパティを要求しないため、呼び出し側も渡すデータを最小限に絞れます。
ネストされた型・optional/readonly修飾はどう引き継がれる?
Pickは選んだプロパティの修飾子をそのまま引き継ぎます。 ?(optional)や readonly が付いたプロパティを抽出すると、新しい型でもその修飾は保持されます。
type Account = {
readonly id: number;
name: string;
nickname?: string;
profile: { bio: string; age: number };
};
type Picked = Pick<Account, "id" | "nickname" | "profile">;
// 結果:
// type Picked = {
// readonly id: number;
// nickname?: string | undefined;
// profile: { bio: string; age: number };
// }
ホバーで確認すると、id には readonly が、nickname には ? が残っているのが分かります。一方で profile のようなネストした型は、トップレベルのキーとして丸ごと選ばれるだけで、内側のプロパティまで加工されることはありません。 profile の中の bio だけを抜き出すといった深い操作をしたい場合は、ネストした型に対してあらためてPickを適用するか、別の型変換を組み合わせます。Pick単体が担うのは、あくまで一段目のキー選択です。
Pickを選ぶ判断軸|残すプロパティが少ないときに使う
PickとOmitは、どちらも「元の型から一部のプロパティを使った新しい型」を作りますが、選び方の軸が逆です。Pickは「残すものを選ぶ」型、Omitは「消すものを選ぶ」型と考えると迷いにくくなります。
| 観点 | Pick | Omit |
|---|---|---|
| 選ぶ対象 | 残したいプロパティ | 除外したいプロパティ |
| 向いている場面 | 残す数が少ないとき | 消す数が少ないとき |
| 書き方 | Pick<T, "残すキー"> |
Omit<T, "消すキー"> |
| 元の型変更への追従 | 残すキーは明示。追加分は手動で足す | 除外キー以外は自動で引き継ぐ |
| 可読性が高いケース | 必要なものが一目で分かる | 何を隠したいかが一目で分かる |
判断の基準はプロパティの数です。残したいプロパティが少数ならPick、大半を残して一部だけ除外したいならOmitを選ぶと、記述が短くなり意図も伝わりやすくなります。たとえば20個のプロパティのうち2つだけ欲しいならPick、1つだけ隠したいならOmitが素直です。ただしこれは絶対のルールではなく、型変更への追従のさせ方や「何を強調して見せたいか」によって選び方が変わる点も覚えておくとよいですよ。
Pickで迷わないための型抽出フロー
どの型操作を使うか迷ったときは、「残す側と消す側、どちらが少ないか」を起点に判断すると素早く選べます。次のフローに当てはめてみてください。
- 残す方が少ない? → Pick で残すキーを並べる
- 消す方が少ない? → Omit で消すキーを並べる
残す側と消す側のどちらが少ないかを意識するだけで、型抽出のほとんどのケースはPickとOmitの2つで判断できます。
Pickとunion型|メンバーの絞り込みには別の型を使う
union型から特定のメンバーだけを取り出したいとき、ついPickを思い浮かべるかもしれません。ただ、その用途にPickは使いません。Pickはオブジェクト型のプロパティを選ぶ型で、"success" | "error" のような文字列リテラルのunionからメンバーを絞り込む操作とは目的が異なります。
unionから一部のメンバーだけを取り出したいときは、union自体を絞り込む Extract を使います。
type Status = "active" | "inactive" | "banned";
type Active = Extract<Status, "active" | "inactive">;
// type Active = "active" | "inactive"
オブジェクト型のプロパティを選ぶのがPick、unionのメンバーを選ぶのは Extract、と役割で覚えておくと混乱しません。
実務でのPick活用シーン|APIレスポンスとフォームの型定義
実務でPickが効くのは、大きな型を「用途ごとに最小化した型」へ派生させたい場面です。代表的なのがAPIレスポンスとフォームの型定義です。
1つ目は、APIレスポンスの大きな型から画面表示に必要な数項目だけを抜き出すケースです。
type UserResponse = {
id: number;
name: string;
email: string;
passwordHash: string;
lastLogin: Date;
createdAt: Date;
};
// 一覧画面で使うのは3項目だけ
type UserListItem = Pick<UserResponse, "id" | "name" | "email">;
passwordHash のような画面に渡したくないプロパティを自然に除外でき、表示用コンポーネントが受け取る型を安全に絞れます。
2つ目は、フォーム入力型をエンティティ型から派生させるケースです。登録フォームで入力する項目だけをPickで抜き出します。
type UserForm = Pick<UserResponse, "name" | "email">;
入力途中で一部だけ埋まっている状態を表したい場合は、こうしたPick派生型をさらに部分的に省略可能へ変換して下書き用の型を組み立てると扱いやすくなります。
そして実務で最も効いてくるのが、元の型を変更すると、そこから派生した型がすべて自動で追従する点です。
私が以前担当したAPIでは、HTTPメソッドごと(POST / PUT / GET)にリクエスト・レスポンスの型を別々に手書きしていました。どれも同じユーザー項目を並べていたため、項目を1つ足したり型を変えたりするたびに全メソッドの型を直さなければならず、更新漏れが起きやすい状態でした。これを、先ほどの UserResponse のようなエンティティ型を1つの源泉にして、メソッドごとの型をPick / Omitで派生させる形に変えたところ、保守がぐっと楽になりました。
// POST(新規作成): id や createdAt はサーバー側で決まるので除外
type CreateUserBody = Omit<UserResponse, "id" | "passwordHash" | "lastLogin" | "createdAt">;
// type CreateUserBody = { name: string; email: string }
// PUT(更新): 更新できる項目だけを残す
type UpdateUserBody = Pick<UserResponse, "name" | "email">;
UserResponse に項目を1つ足すだけで、CreateUserBody も UpdateUserBody も、一覧用の UserListItem もまとめて追従します。手書きで同じ形を複数定義していたときのような更新漏れが起きず、型の源泉を1つに保ったまま、用途別の型を安全に増やせます。
Pickでよくあるエラーと対処|「効かない・赤線が出る」典型ミス
Pickで赤線が出る・思った型にならないときは、まずキー指定とキー名を疑うと原因にたどり着きやすいです。典型的なミスを順に見ていきましょう。
1つ目は、存在しないキーを指定するミスです。Pickの第2引数は元の型のキーに制約されているため、ない名前を渡すとコンパイルエラーになります。
type User = { id: number; name: string };
type Wrong = Pick<User, "nickname">; // 例:Type '"nickname"' does not satisfy the constraint 'keyof User'.(文言はバージョンにより異なる場合あり)
type Right = Pick<User, "name">; // OK
2つ目は、キー名の打ち間違いや大文字小文字の取り違えです。"Name" と "name" は別物として扱われるため、エラー文言は1つ目と同じでも原因は単なるタイポということがよくあります。エラーが出たらまず元の型に同名のキーが本当に存在するかを確認しましょう。
3つ目は、interfaceや型の拡張と併用したときの取りこぼしです。元の型にあとからプロパティを足したつもりが、Pickの第2引数に追記し忘れていると、新しいプロパティは派生型に現れません。Pickは「明示したキーだけ」を残すため、追加したいプロパティはKeysにも書き足す必要があります。
よくある質問
PickとOmitは結局どちらを使えばいい?
残したいプロパティが少数ならPick、大半を残して一部だけ除外したいならOmitを選ぶのが基本です。「残すものを選ぶ=Pick、消すものを選ぶ=Omit」と覚えると迷いません。Omitの詳しい書き方や挙動は、Omit単体の記事で確認できます。
Pickで複数のプロパティをまとめて指定するには?
第2引数に文字列リテラルのunion("a" | "b")として並べます。たとえば Pick<User, "name" | "email"> のように書くと、name と email の2つを持つ型が作れます。3つ以上でも | でつなぐだけで同じように抽出できます。
Pickで存在しないプロパティを指定するとどうなる?
keyofによる制約があるため、コンパイルエラーになります。Type '"xxx"' does not satisfy the constraint 'keyof T'. のような文言が表示されます(文言はTypeScriptバージョンにより異なる場合あり)。指定したキーが元の型に存在するかを確認しましょう。
Pickはunion型に使えますか?
Pickはオブジェクト型のプロパティを抽出する型で、"a" | "b" のようなunionからメンバーを絞り込む用途には使いません。 unionの一部だけを取り出したいときは、ユニオン型自体を絞り込む操作を使います。詳しい考え方はユニオン型の記事で確認できます。
【付録】さらに学びを深めるためのリソース
さらにTypescriptの学習を進めたい方のために、いくつかのリソースを紹介します。
これらのリソースを活用することで、TypeScriptの型システムについてより深い知識を得ることができるでしょう。
おすすめの書籍
ゼロからわかる TypeScript入門
技術評論社から出版されている「ゼロからわかる TypeScript入門」は、プログラミング初心者や本職プログラマーではない方を主な対象にした入門書です。
変数・条件分岐・ループといった基本から、クラスやインターフェース、モジュールまで段階的に学べる構成になっています。最終章ではWeb APIとJSONを使った非同期Webアプリの作成も体験できるので、「実際に動くものを作る」ところまで到達できます。
プロを目指す人のためのTypeScript入門
技術評論社の「プロを目指す人のためのTypeScript入門 安全なコードの書き方から高度な型の使い方まで」、通称 ブルーベリー本 です。
JavaScriptの仕様とTypeScript独自の機能を両方押さえつつ、リテラル型・ユニオン型・keyof型・ジェネリクスなど、高度な型表現まで踏み込んで解説しています。TypeScriptの型システムの表現力を本格的に学べる一冊です。
オンラインで参照できる公式ドキュメント
TypeScript公式ハンドブック
https://www.typescriptlang.org/docs/
TypeScriptの公式ドキュメントです。
intersection型を含む、すべての型システムの機能について詳細な説明があります。
TypeScript Deep Dive
https://basarat.gitbook.io/typescript/
TypeScriptの深い部分まで掘り下げて解説しているオンラインブックです。
無料で読むことができ、intersection型についても詳しく説明されています。
TypeScriptの学習は終わりがありません。
新しい機能が常に追加され、より良い書き方が発見されています。
継続的に学習を続けることで、より良いTypeScriptプログラマーになれるはずです。
まとめ – Pickで型を再利用する判断軸とつまずき対策
この記事では、Pickで既存の型から必要なプロパティだけを抽出する方法を整理しました。
- Pickは既存のオブジェクト型から指定したプロパティだけを抜き出し、元の型を壊さず再利用するユーティリティ型
Pick<Type, Keys>の Keys はkeyof Typeに制約され、複数指定は文字列リテラルのunionで並べる- optionalやreadonlyの修飾は引き継がれ、ネストは一段目のキー選択だけを行う
- 「残す=Pick、消す=Omit」を基準に、残すプロパティが少ないときはPickを選ぶ
- Pickはオブジェクト型用で、union型のメンバー絞り込みには使わない
- APIレスポンスやフォームの型派生に使うと、元の型変更に自動追従して保守が楽になる
Pickは「必要なものだけを残す」というシンプルな発想で、大きな型を用途ごとに最小化し、安全に再利用するための土台になります。
※本記事の本文案はAIを活用して作成していますが、記載している内容およびコードは筆者が実際に調査、検証・実行し、内容の正確性を確認した上で公開しています。






