logo hsb.horse
← スニペット一覧に戻る

Snippets

プロパティ抽出ヘルパー関数

オブジェクトから指定プロパティだけを取り出す関数を生成する。mapByの入れ子や配列変換で型安全なプロパティ抽出を1行にまとめる。

公開日: 更新日:

配列を map で変換する際、オブジェクト全体ではなく特定プロパティだけを抽出したい場面は多い。インラインで書くと冗長になりがちだが、プロパティ抽出関数を事前定義しておけば、map(propsExtractor('id', 'name')) のような簡潔な表現が可能になる。

コード

type LiteralObject = Record<string, unknown>
/**
* オブジェクトから指定プロパティだけを抽出する関数を生成する
*/
export function propsExtractor<
Props extends LiteralObject,
PropKey extends keyof Props,
>(
...props: PropKey[]
): (obj: Props) => Pick<Props, PropKey> {
return (obj: Props) => {
const result: Partial<Props> = {}
for (const prop of props) {
if (Object.hasOwn(obj, prop)) {
result[prop] = obj[prop]
}
}
return result as Pick<Props, PropKey>
}
}

使用例

type User = {
id: string
name: string
email: string
role: string
createdAt: Date
}
const users: User[] = [
{ id: '1', name: 'Alice', email: 'alice@example.com', role: 'admin', createdAt: new Date() },
{ id: '2', name: 'Bob', email: 'bob@example.com', role: 'user', createdAt: new Date() },
]
// IDと名前だけを抽出
const userSummaries = users.map(propsExtractor('id', 'name'))
// => [{ id: '1', name: 'Alice' }, { id: '2', name: 'Bob' }]
// 入れ子のmapでも簡潔に書ける
const departments = [
{ name: 'Engineering', members: users },
{ name: 'Sales', members: users },
]
const summaries = departments.map(dept => ({
department: dept.name,
members: dept.members.map(propsExtractor('id', 'name'))
}))

仕組み

  1. propsExtractor は可変長引数で抽出したいプロパティ名を受け取る
  2. クロージャーとして (obj: Props) => Pick<Props, PropKey> 型の関数を返す
  3. 返された関数は Object.hasOwn でプロパティの存在を確認してから抽出する
  4. TypeScript の Pick ユーティリティ型で、返り値の型を正確に推論する

Object.hasOwn を使うことで、プロトタイプチェーン上のプロパティを誤って抽出しない安全性を確保している。

メリット

  • 可読性が高いmap(propsExtractor('id', 'name')) のように意図が明確
  • 型安全:TypeScript の型推論で抽出後の型が正確に決まる
  • 再利用可能:一度定義すれば、複数箇所で使い回せる
  • 入れ子に強いmapBy の多重適用でも読みやすさを維持できる

注意点

プロパティが存在しない場合は結果に含まれない(undefined にもならない)。すべてのプロパティを含めたい場合は Object.hasOwn のチェックを外す必要がある。また、抽出対象のプロパティが多い場合は、明示的にインターフェースを定義した方が保守性が高いこともある。

応用

  • API レスポンスから必要なフィールドだけを抽出してクライアントに返す
  • ログ出力時に機密情報を含むプロパティを除外する(逆フィルタ版を作る)
  • Redux や Zustand のセレクターで部分的な状態を取り出す
  • GraphQL のフィールド選択に似た部分取得ロジックを実装する

実務メモ

このスニペットは、TypeScript、JavaScript、Functional Programming、Utility の周辺で同じ操作や判定を毎回書きたくない時に向く。小さな補助として切り出しておくと、呼び出し側では意図だけを追いやすい。

逆に、分岐や前提条件が増えて責務が膨らむなら、1本のスニペットに詰め込まない方がよい。手順と helper を分けるか、役割ごとに切り出す方が保守しやすい。