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

exactOptionalPropertyTypes: false
のとき
こう書くと、
1.tstype User = { name: string; email?: string }
こう書いたものとして扱われる
2.tstype User = { name: string; email?: string | undefined }
user.email
にアクセスした結果 undefined
だった場合に、
email
というproperty自体を持っていないから undefined
になっているのかもしれないし、
email
の値が undefiend
になっているから、 undefined
になっているのかもしれない
具体的には、 1.ts
でも 2.ts
でも以下の3つ全てが許容される
tsconst 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つ
tsconst u1: User = { name: 'tarou', email: 'tarou@tarou.com'}
const u2: User = { name: 'tarou' }
以下は許容されない
tsconst u3: User = { name: 'tarou', email: undefined } // error
つまり、 email?: string
な型に undefined
を代入することをできなくなる
ちなみに、
2.ts
については、
exactOptionalPropertyTypes
の有効無効の前後で変化はない

「peropteyrが存在するならば、その型の値が存在する」に変わったということ
何が嬉しいのか?
安全面が向上するケース
tstype 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重のチェックが必要なくなる
tstype User = { name: string; email?: string };
const u1: User = { name: 'tarou' };
if ('email' in u1) {
u1.email; // string (無効だと、string | undefined)
}
tsObject.values(u1).map(v => v); // vはstring(無効だと、string | undefined)
etc.
これは安全性は特に向上してはないが、利便性が良くなったという感じ

exactOptionalPropertyTypes: true
だからといって全てが安全になったわけではない
tsconst 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は出ない
tsfunction f4(t: [string?]) {
let x = t[0]; // string | undefined
t[0] = 'hello';
t[0] = undefined; // Error, 'undefined' not assignable to 'string'
}
参考