Excess Property Checkingとは何か
はじめに
Excess Property Checking(日本語だと「過剰な( or 余計な)プロパティのチェック」だろうか?)というものが何か、理解が曖昧なので整理してみる。
Excess Property Checking
通常、構造的な型システムを採用するTypeScriptにおいて、必須のプロパティさえ満たされていればその他のプロパティについては問題とならない。
ただし、オブジェクトリテラルを変数へ代入するときと関数の引数へ渡すときに限ってExcess Property Checkingの対象となる振る舞いがある。
- Excess Property Checkingの対象
- 変数にオブジェクトリテラルを代入するとき
- 関数の引数にオブジェクトリテラルを渡すとき
TypeScriptの公式ドキュメントから部分的に引用すると
... which validates the object more thoroughly when it is created and assigned to an object type during creation.
「オブジェクト作成時に割り当てる型をより徹底的に検証する」 というような意味合いと思われる説明がある。
例えば、以下のようにオブジェクトリテラルで変数に代入するとき、型アノテーションで指定されている型に含まれていないプロパティを持っていると型エラーになる。(Playground)
type User = {
id: number;
email: string;
};
const userA: User = {
id: 1,
email: "user-a@email.address",
name: "A",
// ↑ 型エラーになる
// Type '{ id: number; email: string; name: string; }' is not assignable to type 'User'.
// Object literal may only specify known properties, and 'name' does not exist in type 'User'.(2322)
};
一方、オブジェクトを変数に代入してから別の変数に代入する場合、必要なプロパティが満たされていればエラーとはならず構造的な型システムとしての通常の振る舞いとなる。(Playground)
type User = {
id: number;
email: string;
};
const userA = {
id: 1,
email: "user-a@email.address",
name: "A",
};
const currentUser: User = userA;
// ↑ OK
構造的な型システムではチェックされない部分をExcess Property Checkingによってチェックすることについて、Effective TypeScriptでは、以下のように
Recognizing excess property checking as a distinct process will help you build a cleaner mental model of TypeScript's type system.
- Item 11: Recognize the Limits of Excess Property Checking -
「別個のプロセスとして認識することでTypeScriptの型システムに関するよりクリーンなメンタルモデルを構築する助けになる。」 というような表現をしている。
なぜこのような機能があるか
Be mindful of TypeScript’s Excess Property Checking · denhox.com - Denat Hoxhaによると、プロパティ名の誤りを防止することが目的という。
This feature exists to protect us from errors that could result from entering wrong property names:
TypeScriptの公式ドキュメントにある例を少し変更した例を用意すると、
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig): { color: string; area: number } {
return {
color: config.color || "red",
area: config.width ? config.width * config.width : 20,
};
}
let blueSquare = createSquare({ colour: "blue", width: 100 });
createSquare({ colour: "blue", width: 100 })
のcolour
は誤ってタイポしていてcreateSquare
関数の引数としてcolor
が渡らない。なのでランタイム上では意図しない振る舞いになる(blue
を返されるはずだけど、実際にはred
が返される)ということが、恐らく構造的型システムだけであれば起こり得るのだろうけど、TypeScriptではこのようなケースをExcess Property Checkingで一定の条件下において防げるということだと思う。
Discussion