【TypeScript】オブジェクトリテラルの型の拡大を防ぐ
どうもフロントエンドエンジニアのoreoです。
今回はTypeScriptのconstアサーションについてまとめます。
1 constアサーションとは?
constアサーションを使用することで、主に以下二つのメリットが得られます。
1-1 宣言と同時に型の拡大を制限することができる
具体的には、Widening Literal Typesを制限することができます。Widening Literal Typesとは、以下例のように、const
によりname
は”シンジ”
のみを許容するリテラル型ですが、let
など別の変数に代入すると、string
として型推論されることです。
const name = "シンジ" //name: "シンジ"
let pilot = name //pilot: string
1-2 型をreadonlyにできる
型をreadonly(書き換え不可)にできます。
2 使い方
constアサーションを利用するには、オブジェクトリテラルの末尾にas const
を記載します。
オブジェクトでの例です。
const profile = {
name: "シンジ",
age: 14
} as const;
//profile: {readonly name: "シンジ"; readonly age: 14;}
//readonlyなので、代入できない
profile.name = "アスカ" ;
//Cannot assign to 'name' because it is a read-only property.
//Widening Literal Typesが制限される
let pilot = profile ;
//pilot: {readonly name: "シンジ"; readonly age: 14;}
配列でも同様です。
const pilots = ["シンジ", "アスカ", "レイ", "マリ"] as const;
//pilots: readonly ["シンジ", "アスカ", "レイ", "マリ"]
//readonlyなので、代入できない
pilots[3] = "トウジ";
//Cannot assign to '3' because it is a read-only property.
//Widening Literal Typesが制限される
let children = pilots;
//children: readonly ["シンジ", "アスカ", "レイ", "マリ"]
オブジェクトリテラルを返す関数で、Widening Literal Typesを制限することもできます
function getPilotOfEVA1() {
return { pilot: "シンジ" };
}
const pilotOfEVA1 = getPilotOfEVA1();
//pilotOfEVA1: {pilot: string;}
function getPilotOfEVA2() {
return { pilot: "アスカ" } as const;
}
const pilotOfEVA2 = getPilotOfEVA2();
//pilotOfEVA2: {readonly pilot: "アスカ";}
3 readonlyとの違い
readonly
は、必要なプロパティにのみつけることができますが、constアサーションは全てのプロパティが対象になります。
//readonlyはプロパティ単位で付与可能
type Profile = { readonly name: "シンジ"; age: 14 };
また、constアサーションは、ネストされているオブジェクトでも全てのプロパティをreadonly
にしてくれます。
以下のようにreadonly
をつけたプロパティがオブジェクトである場合、そのオブジェクトのプロパティはreadonly
になりません。EVA2.pilt.name = "シンジ"
で代入できてしまいます。
type Pilot = {
name: string;
age: number;
};
type EVA = {
readonly pilt: Pilot;
readonly color: string;
};
const EVA2: EVA = {
pilt: {
name: "アスカ",
age: 14
},
color: "red"
};
//エラーになる
EVA2.color = "blue"
//Cannot assign to 'color' because it is a read-only property
//代入できてしまう
EVA2.pilt.name = "シンジ"
constアサーションを使用すると、ネストされたオブジェクトがもつプロパティもreadonly
になります。
const EVA2 = {
pilt: {
name: "アスカ",
age: 14
},
color: "red"
} as const;
//エラーになる
EVA2.color = "blue";
//Cannot assign to 'color' because it is a read-only property.
//エラーになる
EVA2.pilt.name = "シンジ";
//Cannot assign to 'name' because it is a read-only property.
4 最後に
型安全にいきたいですね。
5 参考
constアサーション「as const」 (const assertion) | TypeScript入門『サバイバルTypeScript』
ConditionalTypes I/O - TypeScript3.4 型の強化書 -(電子版) - takepepe - BOOTH
Discussion