直近ではAIにコーディングを任せていたりするのですが、自分の知識が追いついていない内容のコードがいくつも生成されがちなので、その度にドキュメントを確認したりするようにしています。
今回のPartialについても調べたので、自分の備忘録として記事にしました。
Partialとは
サバイバルTypeScriptでは以下のように説明されています。
Partialは、オブジェクトの型Tのすべてのプロパティをオプションプロパティにするユーティリティ型です。
オプションプロパティ、つまり必須のプロパティを任意のプロパティに変更する型という事になります。
interface User {
id: number; // 必須
name: string; // 必須
address: string; //必須
}
type PartialUser = Partial<User>
/*
PartialUserの中身が全てオプショナルに変更される
{
id?: number; // 任意
name?: string; // 任意
address?: string; // 任意
}
*/
// 住所だけ更新したい時、他の項目がなくてもエラーになりません。
const updateAddress: PartialUser = {
address: "東京都..."
}
メリット
元の型と連動する(単一の情報源を保てる)
Partial<User> はUserから自動的に導出されるので、Userを変更すればPartial<User>も自動的に追従します。
interface User {
id: number;
name: string;
address: string;
age: number; // 追加
}
function updateUser(id: number, updates: Partial<User>) { /* ... */ }
updateUser側は一文字も変えなくても、自動的にage?を受け取れるようになります。もし手書きで以下のように定義していたら、修正が必要です。
// 手書きだと User を変えるたびにこっちも直す必要がある(修正漏れの温床)
function updateUser(id: number, updates: {
name?: string;
email?: string;
// age を書き忘れる…というバグが起きる
}) { /* ... */ }
注意点
ネストしたオブジェクトには使えません。
つまり、一番外側のプロパティだけを任意にして、ネストした中身までは任意になりません。
interface User {
id: number;
profile: {
name: string;
age: number;
};
}
type PartialUser = Partial<User>;
{
id?: number;
profile?: { // profile 自体は省略できる(? がついた)
name: string; // でも中身は必須のまま!
age: number; // ? がつかない
};
}
ネストの奥まで再帰的に任意にしたい場合、TypeScript標準の Partial だけではできません。自分で再帰的な型を定義する必要があるようです。
参考