generated at
exactOptionalPropertyTypes
recordの optional?: .. なpropertyに、 undefined 代入することを禁止する
代入の時の話であって、アクセスする時は変わらない
exact.. は、「Exact型」のニュアンスmrsekut







exactOptionalPropertyTypes: false のとき
こう書くと、
1.ts
type User = { name: string; email?: string }
こう書いたものとして扱われる
2.ts
type User = { name: string; email?: string | undefined }
user.email にアクセスした結果 undefined だった場合に、
email というproperty自体を持っていないから undefined になっているのかもしれないし、
email の値が undefiend になっているから、 undefined になっているのかもしれない
具体的には、 1.ts でも 2.ts でも以下の3つ全てが許容される
ts
const u1: User = { name: 'tarou', email: 'tarou@tarou.com'} // 両方あり const u2: User = { name: 'tarou' } // emailはfield自体ない const u3: User = { name: 'tarou', email: undefined } // emailにundefined
この差は型の表現では同じものとして扱われるが、実行時の挙動が異なる
つまり以下の2つが同一視されていることになる
そのproperty自体が存在しない
そのpropertyの値が undefined である



exactOptionalPropertyTypes: true にするとどうなるか
上の 1.ts のように定義した場合、
許容されるのは以下の2つ
ts
const u1: User = { name: 'tarou', email: 'tarou@tarou.com'} const u2: User = { name: 'tarou' }
以下は許容されない
ts
const u3: User = { name: 'tarou', email: undefined } // error
つまり、 email?: string な型に undefined を代入することをできなくなる
ちなみに、 2.ts については、 exactOptionalPropertyTypes の有効無効の前後で変化はないmrsekut
「peropteyrが存在するならば、その型の値が存在する」に変わったということ



何が嬉しいのか?
安全面が向上するケース
ts
type User = { name: string; email?: string }; const u: User = { name: 'Daniel', email: undefined // error }; const q: { name: string } = u; const r = { age: 3, ...q }; const t = r.age; // 型はnumber、値はundefined (矛盾)
無効の場合、このコードがerrorなしで書けてしまう
t の値は undefined だが、型は number と推論されているため矛盾が生じている
有効にした場合、 undefined を代入する際にerrorが生じる
利便性の向上
propertyを列挙する系の処理をする時に、2重のチェックが必要なくなる
例: in演算子で絞り込んだ時
ts
type User = { name: string; email?: string }; const u1: User = { name: 'tarou' }; if ('email' in u1) { u1.email; // string (無効だと、string | undefined) }
ts
Object.values(u1).map(v => v); // vはstring(無効だと、string | undefined)
etc.
これは安全性は特に向上してはないが、利便性が良くなったという感じmrsekut



exactOptionalPropertyTypes: true だからといって全てが安全になったわけではない
ts
const x: { a: number; b: boolean } = { a: 42, b: true }; const y: { a: number } = x; // ok const z: { a: number; b?: string } = y; // ok const b = z.b; // 値はtrue、型はstring|undefined (矛盾)
有効にしてもerrorは出ない




ts
function f4(t: [string?]) { let x = t[0]; // string | undefined t[0] = 'hello'; t[0] = undefined; // Error, 'undefined' not assignable to 'string' }




参考