mongolyyのブログ

開発(Javascript, Typescript, React, Next.js)や開発手法(スクラム, アジャイル)、勉強したことについて色々書ければと。

TypeScriptにおいて、とある型の一部のプロパティのみを必須にする型エイリアスを定義する

何がしたいか?

TypeScriptにおいて、とある型の一部のプロパティのみを必須にした型を作りたいとします。
次の例で言うと、とある型(User)を元に、一部のプロパティ(age)を必須にした新たな型(AdultUser)を作りたいとします。

type User = {
  name: string
  mail: string
  age?: number
  phone?: string
}

// 成人のユーザーの年齢プロパティは必須
type AdultUser = {
  name: string
  mail: string
  age: number
  phone?: string
}

// ageがundefinedになっていることを防ぎたい
const adult: AdultUser = {
  name: 'テスト太郎',
  mail: 'test@example.com'
}
// 次のエラーが発生する
// Property 'age' is missing in type '{ name: string; mail: string; }' but required in type 'AdultUser'.

上記の例の場合はプロパティの数が少なかったので良かったですが、実際はもっと項目が多かったり、Userのプロパティが頻繁に変更されるとミスが出てくると思います。
今回はそのために簡単な型エイリアスを作りましたので、紹介したいと思います。

どんな型エイリアス

type SomeRequired<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>

Utility Typesを使いました。
Utility Typesについては公式のドキュメントを読んでください。 www.typescriptlang.org

新たに定義したSomeRequiredを使うと、次のようにAdultUser型を定義することができます。

type AdultUser = SomeRequired<User, 'age'>

const adult: AdultUser = {
  name: 'テスト太郎',
  mail: 'test@example.com'
}
// 次のエラーが発生する
// Type '{ name: string; mail: string; }' is not assignable to type 'AdultUser'.
//   Property 'age' is missing in type '{ name: string; mail: string; }' but required in type 'Required<Pick<User, "age">>'.

また、OmitPick と同様に、| を使うことで複数の項目を必須にすることができます。

type NewAdultUser = SomeRequired<User, 'age' | 'phone'>

const newAdult: NewAdultUser = {
  name: 'テスト太郎',
  mail: 'test@example.com',
}
// Type '{ name: string; mail: string; }' is not assignable to type 'NewAdultUser'.
//   Type '{ name: string; mail: string; }' is missing the following properties from type 'Required<Pick<User, "age" | "phone">>': age, phone

終わりに

Utility typesを知っている方なら簡単にわかる型エイリアスだと思いますが、知らなかった方は是非使ってみてください!