JavaScript/TypeScriptではオブジェクトのプロパティにアクセスする表現をプロパティアクセサーという。
プロパティアクセサーには2つの記法、dot記法とbracket記法がある。
const obj = { a: 2 }; // dot notation obj.a = 1; const dot = obj.a; // bracket notation obj["a"] = 1; const bracket = obj["a"];
これらはECMAScriptによって規定されている。
Properties are accessed by name, using either the dot notation ...
or the bracket notation
ECMAScript 10th 12.3.2 Property Accessors
TypeScript 型推論
ではTypeScriptの型推論はこれらをどう調理するのか。
検証してみた。
各記法でオブジェクトプロパティへアクセスし、型推論結果をコメントに記した。
version: TypeScript 3.7.3 (VSCode 1.41.0)
type Side = "A" | "B"; // deterministic const side = "A"; const obj = { A: 1, B: "hello" }; const dot = obj.A; // number const bracketRaw = obj["A"]; // number const bracketVar = obj[side]; // number //// undefined property const side2 = "C"; const dot2 = obj.C; // ERROR: Property 'C' does not exist on type '{ A: number; B: string; }'. ts(2339) obj.C = 1; // ERROR: Property 'C' does not exist on type '{ A: number; B: string; }'. ts(2339) const bracketRaw2 = obj["C"]; // any const bracketVar2 = obj[side2]; // any obj["C"] = 1; // no error // undeterministic function tester(side: Side) { const obja = { A: 1, B: "hello" }; const dot = obja.A; // number const bracketRaw = obja["A"]; // number const bracketVar = obja[side]; // string | number }
TSはbracket記法でも賢く型推論してくれる。
そしてdot記法とbracket記法で異なる推論をおこなっている。
dot記法の場合、未定義 (undefinedな) プロパティへのアクセスはコンパイラによるErrorとして扱う.
bracket記法の場合、未定義 (undefinedな) プロパティへのアクセスはany型として扱う.
伝統的にbracket記法をdynamic propertyとして利用するのでundefinedにアクセスできないと困る、という背景なのかと思う。
dynamic propertyでも事前に型定義をしておけばきちんと型推論される (tester内でobja[side]
が正しくstring | number
に推論されている) のでとても助かる。
結言
TypeScriptはオブジェクトプロパティアクセサーのdot記法とbracket記法で異なる型推論をおこなう。
どちらの記法でも充分な型推論をおこなってくれるが、undefined propertyをdot記法はエラー、bracket記法はanyとして扱う。
TypeScriptはいいぞ。