問題の背景
TypeScriptは、デフォルトでオブジェクトリテラルの型を緩めて解釈します。すなわち、オブジェクトに含まれる余剰なプロパティを無視されてしまいます。例えば、次のようなコードではエラーは発生しません。
type User = {
name: string;
}
function putStorage(user: User) {
window.sessionStorage.setItem('user', JSON.stringify(user));
}
const john = {
name: "John",
age: 30 // 余剰なプロパティ
};
putStorage(john); // エラーなし
この例の場合、渡されたオブジェクトをsession storageに保存しているため、
全く予期せぬ値がsession Storageに保管されてしまっていても、静的エラーで気づくことができません。
StrictPropertyCheck型の導入
StrictPropertyCheck
という型を作成します。これは、余剰なプロパティをエラーとして検出するために使用します。
type StrictPropertyCheck<T, TExpected> = keyof T extends keyof TExpected ? T: `${Exclude<Extract<keyof T,string|number>, Extract<keyof TExpected,string|number>>} is excess property `;
この型は、2つの型引数を受け取ります。
-
T
:検査対象のオブジェクト型。 -
TExpected
:期待されるプロパティの型。
T のプロパティが TExpected のプロパティと一致する場合、T をそのまま返します。これは、型チェックが成功したことを示します。
T のプロパティのいずれかが TExpected のプロパティと一致しない場合(Tに余剰プロパティが含まれる場合)エラーメッセージを生成します。このエラーメッセージには、T 型の余剰プロパティが含まれていることを示す情報が含まれます。
※keyof
では予測される型はstring | number | symbol
であり
symbol
型はオブジェクトリテラルで出力できないためstring | number
だけ出力するようにしています。
StrictPropertyCheckの活用
これを活用して、余剰なプロパティをエラーとして検出する関数を作成します。
type StrictPropertyCheck<T, TExpected> = keyof T extends keyof TExpected ? T: `${Exclude<Extract<keyof T,string|number>, Extract<keyof TExpected,string|number>>} is excess property `;
type User = {
name: string;
}
function putStorage<T extends User>(user: StrictPropertyCheck<T,User>) {
window.sessionStorage.setItem('user', JSON.stringify(user));
}
const john = {
name: "John",
age: 30 ,// 余剰なプロパティ
};
putStorage(john); // エラー: Argument of type '{ name: string; age: number; }' is not assignable to parameter of type '"age is excess property "'
このように、StrictPropertyCheck
型を使用することで、余剰なプロパティが関数の呼び出し時にエラーとして検出されるようになりました。