Menu

TypeScriptのPick: 型からプロパティを選び出す(サンプル付き)

Pick<T, K> は、T のプロパティのうちキーが K に含まれるものだけを持つ型を作ります。1つや複数のキーの Pick、キーのチェックのされ方、Pick と Omit の違い、ネストした型からの Pick、型付きの pick() 関数、値の型によるプロパティの選択を解説します。

このページのコードはエディタで実行できます - 編集してすぐに結果を確認できます。

Pick<T, K> は、T のプロパティのうち K で名前を挙げたものだけを持つオブジェクト型を作る組み込みのユーティリティ型です。関数やコンポーネントが大きな型のいくつかのフィールドだけを必要とするときに使います:

renderPreview は、使うものだけを求めているので、完全な User も普通の { id, name } オブジェクトも受け付けます。そのおかげで呼び出しやすく、テストもしやすくなります。Pick は型だけのものです。完全な ada オブジェクトは、実行時には5つのプロパティをすべて持ったままです。

構文とキーのチェック

Pick<Type, Keys>

Keys は1つのキーかキーのユニオン型で、どれも Type に存在しなければなりません。TypeScriptの標準ライブラリの定義は、それを制約にしています:

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

K extends keyof T があるので、打ち間違えたキーや存在しないキーはコンパイルエラーになり、エディターはキー名を補完できます:

エラーは error TS2344: Type '"cost"' does not satisfy the constraint 'keyof Product'. です。キーがチェックされない Omit とはここが違います。

Pick は readonly と省略可能を保つ

Pick は T のキーに対してマップするので、選んだ各プロパティは修飾子を保ちます:

最後の行が { id: 8 } を表示するのは、readonly がコンパイル時だけのチェックだからです。代入は報告され、@ts-expect-error で抑えられましたが、それでも実行されました。選ぶと同時に修飾子を変えるには、結果を囲みます: Partial<Pick<Account, "plan">> や Required<Pick<Account, "email">>。

Pick と Omit

Pick は残すものを、Omit は捨てるものを名指しします。今はどちらも同じ結果になりますが、元の型が大きくなったときの振る舞いが違います:

Pick<T, K>Omit<T, K>
並べるもの残すキー取り除くキー
T の新しいプロパティ含まれない自動的に含まれる
K の中の知らないキーコンパイルエラー(TS2344)黙って受け付ける
向いている用途APIのレスポンス、公開用のビュー、props「秘密以外すべて」

サーバーから外に出るデータには、Pick のほうが安全なデフォルトです。誰かが意図的に追加しない限り、型には何も現れません。

ネストした型から Pick する

Pick が見るのはトップレベルのキーだけです。Pick<Customer, "address.city"> のようなドット区切りのパスはネストした Pick ではなく、エラー(TS2344)です。インデックスアクセス型でネストした型に届き、そこから選びましょう:

Customer["address"] は address プロパティの型です。同じ構文で配列の要素にも届きます。orders: Order[] というプロパティなら、Customer["orders"][number] は Order です。

型付きの pick() 関数

Pick は実行時には何もしません。小さなジェネリック関数で、選んだプロパティを新しいオブジェクトにコピーし、ちょうど Pick<T, K> を返せます:

K extends keyof T があるので、TypeScriptは文字列の引数から K を推論でき、戻り値の型はちょうど選んだキーを持ちます。空のオブジェクトはまだそれらのプロパティを持っていないので、{} as Pick<T, K> のアサーションが必要です。ループがそれを埋めます。

値の型でプロパティを選ぶ

Pick はキーの名前で選びます。プロパティの型で選ぶには(たとえば「文字列のフィールドすべて」)、キーを絞り込む マップ型 を書きます:

as 句は、型が一致するキーをそのキー自身に、それ以外を never にマップし、never のキーは捨てられます。細かい点が1つあります。省略可能なプロパティの型は undefined を含むので、省略可能な subtitle?: string はここでは string として数えられません。それも含めるには string | undefined と照らし合わせます。

よくある質問

TypeScriptの Pick は何をしますか?

Pick<T, K> は、T のプロパティのうちキーが K に含まれるものだけを持つオブジェクト型を作ります。User が id と name とほかのプロパティを持つなら、Pick<User, "id" | "name"> は { id: number; name: string } です。型にだけ働き、実行時にオブジェクトから何も取り除きません。

Pick と Omit の違いは何ですか?

Pick は残すプロパティを、Omit は取り除くプロパティを並べます。元の型にプロパティが増えたとき、Omit は自動的にそれを含め、Pick は含めません。また、Pick はキーが型に存在するかをチェックしますが、Omit はどんなキーでも受け付けます。

TypeScriptで複数のプロパティを Pick するには?

キーのユニオン型を渡します: Pick<User, "id" | "name" | "email">。キーはすべて User に存在しなければならず、そうでなければコンパイラーはエラー TS2344 を報告します。

TypeScriptでネストしたプロパティを Pick するには?

Pick が選べるのはトップレベルのプロパティだけです。インデックスアクセス型でネストした型に届き、そこから選びます: Pick<User["address"], "city">。ネストの構造を保つには組み合わせます: Pick<User, "id"> & { address: Pick<User["address"], "city"> }。

Pick は readonly や省略可能の修飾子を保ちますか?

保ちます。Pick は T のキーに対するマップ型なので、T で readonly や省略可能だったプロパティは、選んだ型でもそのままです。

Coddy programming languages illustration

Coddyでコードを学ぼう

始める