exactOptionalPropertyTypes
recordのoptional?: ..なpropertyに、undefinedを代入することを禁止する
代入の時の話であって、アクセスする時は変わらない
exact..は、「Exact型」のニュアンスmrsekut.icon
exactOptionalPropertyTypes: falseのとき
こう書くと、
code:1.ts
type User = { name: string; email?: string }
こう書いたものとして扱われる
code:2.ts
type User = { name: string; email?: string | undefined }
user.emailにアクセスした結果undefinedだった場合に、
emailというproperty自体を持っていないからundefinedになっているのかもしれないし、
emailの値がundefiendになっているから、undefinedになっているのかもしれない
具体的には、1.tsでも2.tsでも以下の3つ全てが許容される
code: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つ
code:ts
const u1: User = { name: 'tarou', email: 'tarou@tarou.com'}
const u2: User = { name: 'tarou' }
以下は許容されない
code:ts
const u3: User = { name: 'tarou', email: undefined } // error
つまり、email?: stringな型にundefinedを代入することをできなくなる
ちなみに、2.tsについては、exactOptionalPropertyTypesの有効無効の前後で変化はないmrsekut.icon
「peropteyrが存在するならば、その型の値が存在する」に変わったということ
何が嬉しいのか?
安全面が向上するケース
code: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重のチェックが必要なくなる
code:ts
type User = { name: string; email?: string };
const u1: User = { name: 'tarou' };
if ('email' in u1) {
u1.email; // string (無効だと、string | undefined)
}
code:ts
Object.values(u1).map(v => v); // vはstring(無効だと、string | undefined)
etc.
これは安全性は特に向上してはないが、利便性が良くなったという感じmrsekut.icon
exactOptionalPropertyTypes: trueだからといって全てが安全になったわけではない
code: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は出ない
code:ts
let x = t0; // string | undefined t0 = undefined; // Error, 'undefined' not assignable to 'string' }
参考