TypeScriptのユーティリティ型で似た型を手書きしない
TypeScriptのユーティリティ型で似た型を手書きしない
似たような型を毎回手書きしていて、フィールドを1つ足すたびにあちこち直す羽目になって修正漏れが出たので、ユーティリティ型を使うようにしたときのメモです。
TypeScriptには既存の型から新しい型を導く ユーティリティ型 が標準で用意されていて、これを使うと「元の型が変われば派生型も自動で追従する」状態を作れます。ここでは自分がよく使う4つを整理します。
題材として、次のユーザー型を共通の元データとして使います。
type User = {
id: string
name: string
email: string
age: number
createdAt: Date
}
Partial:すべてを任意にする
Partial<T> は、型 T のすべてのプロパティを省略可能(? 付き)にします。「一部だけ更新する」関数の引数によく合います。
function updateUser(id: string, changes: Partial<User>) {
// changes は { name?: string; email?: string; ... } のように全部任意
}
updateUser('u1', { email: 'new@example.com' }) // OK:一部だけでよい
更新APIのように「渡されたフィールドだけ反映する」処理で重宝します。逆に、すべてを必須化したいときは Required<T> を使います。
Pick:必要なプロパティだけ取り出す
Pick<T, Keys> は、型から指定したプロパティだけを抜き出します。一覧表示用に「最小限のフィールドだけ持つ型」を作りたいときに便利です。
type UserListItem = Pick<User, 'id' | 'name'>
// => { id: string; name: string }
元の User に項目が増えても、UserListItem は id と name だけのまま保たれます。
Omit:特定のプロパティを除外する
Omit<T, Keys> は Pick の逆で、指定したプロパティを 除いた 型を作ります。「サーバーが自動で付与するフィールドは、作成時の入力には含めたくない」といったケースにぴったりです。
type CreateUserInput = Omit<User, 'id' | 'createdAt'>
// => { name: string; email: string; age: number }
id と createdAt はサーバー側で決まるので、入力フォームの型からは外しておく、という設計が型で表現できます。
Pick と Omit の使い分けの目安はこんな感じです。
| 状況 | 向いている型 |
|---|---|
| 残したい項目が少ない | Pick |
| 除きたい項目が少ない | Omit |
Record:キーと値の対応を作る
Record<Keys, Value> は、決まったキー集合に対して同じ型の値を持つオブジェクトを表します。区分ごとの設定をまとめるときによく使います。
type Role = 'admin' | 'editor' | 'viewer'
const permissions: Record<Role, boolean> = {
admin: true,
editor: true,
viewer: false,
}
Record<Role, boolean> としておくと、Role に新しい値を足したときに「キーが足りない」とコンパイルエラーで気づけます。設定の書き漏れを型で防げるのが大きな利点です。これは便利。
組み合わせて使う
ユーティリティ型は組み合わせると効果が一段と高まります。たとえば「更新フォーム用に、一部のフィールドだけを任意にした型」はこう書けます。
// プロフィール編集:name と email だけ、しかも任意で受け取る
type ProfileUpdate = Partial<Pick<User, 'name' | 'email'>>
// => { name?: string; email?: string }
こんなふうに小さな型を重ねていくと、元の User を1か所直すだけで関連する型がすべて追従します。型の定義が増えても、真実の源(source of truth)が1つに保たれるわけです。
まとめ
Partial/Required… 任意・必須を一括で切り替えるPick/Omit… 必要な、あるいは不要なプロパティを選ぶRecord… キー集合に対する値のマップを作り、書き漏れを防ぐ
まずは「同じようなオブジェクト型を2つ以上書きそうになったら、片方を派生にできないか」を考えるところから始めてみるとよさそうです。標準のユーティリティ型はTypeScript公式ハンドブックに一覧があるので、手元に開いておくと迷いません。以上です。