概要
TypeScriptのtype assersionやsatisfiesについて調べていましたが、まずはwidening
について理解していないと説明ができないと感じ、まずはwidening
についてまとめてみました。
型推論について
widening
の前に、型推論についても少し触れておきます。
型推論とは、型注釈(アノテーション)しなくても、TypeScript
が文脈を読んで型を推論してくれる機能です。
そして、今まで勘違いしていたんですが、
const foo = "foo";
のような、const宣言だとstring
型で型推論されているかと思っていましたが実は、
const foo: "foo" = "foo";
のように"foo"という文字列リテラル型として型推論されています。要するに"foo"
というプリミティブ値(オブジェクトではなく、メソッドを持たない値)しか代入できません。
逆に、再代入可能なlet
宣言だと、
let bar = "bar";
// ↓
let bar: string = "bar";
のようにstring型に推論されるため、
let bar = "bar";
bar = "barbar"
と再代入しても、同じstring型なので、怒られません。
数値リテラル型や真偽値リテラル型についても同様で、
const num = 100;
// 100型という数値リテラル型に推論される
const shin = true;
// true型(真偽値リテラル型)に推論される
配列やオブジェクトの場合
配列やオブジェクトの場合は注意が必要で、const宣言とlet宣言が同じ型推論となります。const宣言だからと安心していたら大変なことになります。
let letArr = [0, 1, 2, 3]; // : number[]型で推論される
const cstArr = [0, 1, 2, 3]; // : number[]型で推論される
cstArr[0] = 100; // cstArrはconst宣言なのに、再代入しても怒られない
let letObj = { a: "hoge", b: 777 }; // : { a: string; b: number; }型で推論される
let cstObj = { a: "hoge", b: 777 }; // : { a: string; b: number; }型で推論される
cstObj.a = "fuga"; // cstObjはconst宣言なのに、再代入しても怒られない
配列、オブジェクトの場合は、配列の各要素または、各プロパティ値は、プリミティブ型とはならないので、注意が必要です。
型がwideningするとは
const foo = "foo"; // foo: "foo"型
let bar = foo; //bar: string型
bar = "bar"; //怒られない
このケースのように、型が:"foo"
→:string
のように緩くなることをwideningすると言います。
参考