Literal 型でアノテーションやアサーションをすると、NonWidening な Literal 型になる
let str: 'Hello' = 'Hello';
let str2 = str;
str2 = 'Goodbye'; // error: Type '"Goodbye"' is not assignable to type '"Hello"'.
let str = 'Hello' as 'Hello';
let str2 = str;
str2 = 'Goodbye'; // error: Type '"Goodbye"' is not assignable to type '"Hello"'.
このように変数に対して Literal 型でアノテーション(型注釈)やアサーションを行うと、その変数を代入した別の変数も同じ Literal 型として型推論される。このような性質を NonWidening と呼ぶ。
const 宣言による Literal 型は Widening な Literal 型になる
const str = 'Hello'; // Literal 型 'Hello' として型推論される
let str2 = str;
str2 = 'Goodbye';
console.log(str2); // Goodbye
このように const で宣言された変数は、Literal 型 ‘Hello’ として型推論されるが、その変数を代入した別の変数は Literal 型ではなく、string 型として型推論される。そのため、’Hello’ 以外の文字列を代入できる。この性質は Widening と呼ばれる。
as const アサーションにより NonWidening かつ readonly にできる
「as const」アサーションを使用すれば、型推論の Widening を抑制することができる。
let str = 'Hello' as const; // Literal 型の "Hello" として型推論される。
let arr = [1, 2, 3] as const; // readonly [1, 2, 3] として型推論される。
let obj = {
name: 'Tom',
age: 33
} as const;
// {
// readonly name: "Tom";
// readonly age: 33;
// }
// のように型推論される。