UGA Boxxx

つぶやきの延長のつもりで、知ったこと思ったこと書いてます

【TypeScript】Mapped Types

Software Design (ソフトウェアデザイン) 2024年05月号を読んでMapped Typesを知った

Mapped Typesは「ある型から条件を満たした別の型に変換する」という型変換ができる機能

本では使い方の例として、2つのモデル(User, DraftUser)で説明されている

UserとDraftUserの違いはidとcreatedAtがオプショナルかどうかの違いがある

type User = {
  id: string;
  name: string;
  createdAt: number;
}
type DraftUser = {
  id?: string;
  name: string;
  createdAt?: number;
}

UserとDraftUserが対応関係にある場合、独立して定義していると変更漏れが発生する恐れがある

なのでMapped Typesを使ってOptionalユーティリティを作りこれを以下のように書き直すことができる

type Optional<T extends {}, K extends keyof T> = Omit<T, K> & {
    [k in K]?: T[k] | undefined;
};
type DraftUser = Optional<User, "id" | "createdAt">;

やっていることは

  • 型引数に対してextendsで推論しやすい型制約を設定する
  • keyof T に対してループ展開([k in K]はループ展開と考えてよい)
  • T[k]のサブタイプを確認し、プロパティの型を条件型で表現する

本にあったTIPSとして、このままだとIDEでの型情報が読みづらいのでIdentity<T>ユーティリティも作ると読みやすくなるの知らなかった

type Identify<T> = T extends infer U ? {
  [K in keyof U]: K
} : never;

type DraftUser2 = Identify<Optional<User, "id" | "createdAt">>