🎯

【type-challengesに挑戦!】Pick の解答と解説

に公開

はじめに

この記事は、type-challenges の問題を解説するシリーズです。今回は Pick の問題に挑戦します。

問題

TypeScript の組み込みユーティリティ型 Pick<T, K> を使用せずに実装します。

Pick<T, K> は、型 T から指定したプロパティ K のみを選択して新しい型を構築します。

例:

interface Todo {
  title: string
  description: string
  completed: boolean
}

type TodoPreview = MyPick<Todo, "title" | "completed">

const todo: TodoPreview = {
  title: "Clean room",
  completed: false
}

解答

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

解説

ステップ 1: 型パラメータの定義

type MyPick<T, K extends keyof T>

2 つの型パラメータを定義しています:

  • T: 元となる型(例: Todo インターフェース)
  • K: 抽出したいプロパティ名の型

ステップ 2: K extends keyof T の制約

K extends keyof T

この部分が非常に重要です:

  • keyof T: 型 T のすべてのプロパティ名をユニオン型として取得
    • 例: keyof Todo は "title" | "description" | "completed"
  • K extends keyof T: K が T のプロパティ名であることを制約
    • これにより、存在しないプロパティを指定するとコンパイルエラーになります

型安全性の例:

// ✅ OK: "title" は Todo のプロパティ
type ValidPick = MyPick<Todo, "title">;

// ❌ エラー: "invalid" は Todo のプロパティではない
type InvalidPick = MyPick<Todo, "invalid">;
// Type '"invalid"' does not satisfy the constraint '"title" | "description" | "completed"'.

ステップ 3: マップド型 [P in K]: T[P]

{
  [P in K]: T[P];
}

この構文はマップド型と呼ばれ、以下の処理を行います:

  1. [P in K]: K に含まれる各プロパティ名を P として反復処理
  2. T[P]: 元の型 T から、プロパティ P の型を取得(インデックスアクセス型)

具体例で見てみましょう:

type TodoTitle = MyPick<Todo, "title">;

この場合、以下のように展開されます:

  1. K は "title"
  2. P in "title" で P が "title" になる
  3. T[P] つまり Todo["title"] で string 型が取得される
  4. 結果: { title: string }

複数のプロパティを指定した場合:

type TodoPreview = MyPick<Todo, "title" | "completed">;

展開プロセス:

  1. K は "title" | "completed"
  2. P in "title" | "completed" で P が順に "title", "completed" になる
  3. それぞれの型を取得:
    • Todo["title"] → string
    • Todo["completed"] → boolean
  4. 結果: { title: string; completed: boolean; }

まとめ

この記事では、type-challenges の Pick 問題を通じて、以下の TypeScript の重要な概念を学びました:

  1. ジェネリック型パラメータ: 再利用可能な型定義の作成
  2. keyof 演算子: 型のプロパティ名をユニオン型として取得
  3. 型制約 (extends): 型パラメータに制限を設けて型安全性を確保
  4. マップド型: 既存の型からプロパティを反復的に変換
  5. インデックスアクセス型 (T[P]): 型からプロパティの型を取得

参考リンク

Discussion