Closed4

TypeScript の Optional Property を型で判定する

uttkuttk

やりたいこと

以下のような Optional Property を持つ型があるとします👇

type Hoge = {
  foo: string
  bar: number | undefined
  hoge?: string
}

上記の型から Optional Property である hoge のみを取り出す型関数を作りたいです 👇

type Hoge = {
  foo: string
  bar: number | undefined
  hoge?: string
}

type OnlyOptionalProperties = PickOptionalProperties<Hoge>;
// 結果は `{ hoge?: string }` としたい
uttkuttk

実現方法

以下のような型を作成することで実現できます👇

type PickOptionalProperties<T extends object> = Pick<T, {
  [K in keyof T]: T[K] extends Required<T>[K] ? never : K
}[keyof T]>
uttkuttk

解説

この場合の肝となるのは Union 型をどうやって排除するかというところですが、組み込み型である Required を使うことで、 Optional Property のみに型の差分を作り出すことできます 👇

type A = Required<Hoge>;
/*
  {
    foo: string
    bar: number | undefined
    hoge: string // 👈 Optional Property だけ型が変わってる
  }
*/

これを利用することで、Optional Property か判定することができます。
具体的には以下の部分ですね👇

// この条件式の場合 Optional Property だけが `K` を返す
[K in keyof T]: T[K] extends Required<T>[K] ? never : K

あとはプロパティ名を値に持つオブジェクト型を作って、そこからプロパティ名のUnion型に変換して、Pick を使って Optional Property のみを抜き出すという感じです 👇

type PickOptionalProperties<T extends object> = Pick<
  T, 
  // プロパティ名を値に持つオブジェクト型を作って、そこからプロパティ名のUnion型に変換
  {
    [K in keyof T]: T[K] extends Required<T>[K] ? never : K
  }[keyof T]
>
このスクラップは2023/01/09にクローズされました