メインコンテンツまでスキップ

constアサーション「as const」 (const assertion)

変数宣言のときに、末尾にas constをつけるとその値をreadonlyにした上で、リテラル型にしてくれます。
プリミティブ型の値だとそこまでうま味を感じにくいですが、配列やオブジェクトリテラルに対して使うと便利です。

ts
const str1 = "hello";
const str1: "hello"
const str2 = "hello" as const; // これはas constがなくても同じ
const str2: "hello"
const array1 = [1, 2, 3];
const array1: number[]
const array2 = [1, 2, 3] as const;
const array2: readonly [1, 2, 3]
const obj1 = {
const obj1: { name: string; no: number; genre: string; height: number; weight: number; }
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
};
const obj2 = {
const obj2: { readonly name: "pikachu"; readonly no: 25; readonly genre: "mouse pokémon"; readonly height: 0.4; readonly weight: 6; }
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
} as const;
ts
const str1 = "hello";
const str1: "hello"
const str2 = "hello" as const; // これはas constがなくても同じ
const str2: "hello"
const array1 = [1, 2, 3];
const array1: number[]
const array2 = [1, 2, 3] as const;
const array2: readonly [1, 2, 3]
const obj1 = {
const obj1: { name: string; no: number; genre: string; height: number; weight: number; }
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
};
const obj2 = {
const obj2: { readonly name: "pikachu"; readonly no: 25; readonly genre: "mouse pokémon"; readonly height: 0.4; readonly weight: 6; }
name: "pikachu",
no: 25,
genre: "mouse pokémon",
height: 0.4,
weight: 6.0,
} as const;

readonlyになるため代入はもちろんできません。

ts
array1[0] = 4;
array2[0] = 4;
Cannot assign to '0' because it is a read-only property.2540Cannot assign to '0' because it is a read-only property.
obj1.name = "raichu";
obj2.name = "raichu";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.
ts
array1[0] = 4;
array2[0] = 4;
Cannot assign to '0' because it is a read-only property.2540Cannot assign to '0' because it is a read-only property.
obj1.name = "raichu";
obj2.name = "raichu";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.

readonlyconst assertionの違い

どちらもオブジェクトのプロパティをreadonlyにする機能は同じですが、以下が異なります。

readonlyはプロパティごとにつけられる

const assertionはオブジェクト全体に対する宣言なので、すべてのプロパティが対象になりますが、readonlyは必要なプロパティのみにつけることができます。

const assertionは再帰的にreadonlyにできる

オブジェクトの中にオブジェクトがあるときの挙動が異なります。たとえば次のようなオブジェクトがあるとします。

ts
type Country = {
name: string;
capitalCity: string;
};
 
type Continent = {
readonly name: string;
readonly canada: Country;
readonly us: Country;
readonly mexico: Country;
};
 
const america: Continent = {
name: "North American Continent",
canada: {
name: "Republic of Canada",
capitalCity: "Ottawa",
},
us: {
name: "United States of America",
capitalCity: "Washington, D.C.",
},
mexico: {
name: "United Mexican States",
capitalCity: "Mexico City",
},
};
ts
type Country = {
name: string;
capitalCity: string;
};
 
type Continent = {
readonly name: string;
readonly canada: Country;
readonly us: Country;
readonly mexico: Country;
};
 
const america: Continent = {
name: "North American Continent",
canada: {
name: "Republic of Canada",
capitalCity: "Ottawa",
},
us: {
name: "United States of America",
capitalCity: "Washington, D.C.",
},
mexico: {
name: "United Mexican States",
capitalCity: "Mexico City",
},
};

ここでContinentのタイプエイリアスがもつプロパティはすべてreadonlyです。よって次のようなことはできません。

ts
america.name = "African Continent";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.
america.canada = {
Cannot assign to 'canada' because it is a read-only property.2540Cannot assign to 'canada' because it is a read-only property.
name: "Republic of Côte d'Ivoire",
capitalCity: "Yamoussoukro",
};
ts
america.name = "African Continent";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.
america.canada = {
Cannot assign to 'canada' because it is a read-only property.2540Cannot assign to 'canada' because it is a read-only property.
name: "Republic of Côte d'Ivoire",
capitalCity: "Yamoussoukro",
};

しかしながら、次のようなことは問題なくできてしまいます。

ts
america.canada.name = "Republic of Côte d'Ivoire";
america.canada.capitalCity = "Yamoussoukro";
ts
america.canada.name = "Republic of Côte d'Ivoire";
america.canada.capitalCity = "Yamoussoukro";

これはreadonlyをつけたプロパティがオブジェクトである場合に、そのオブジェクトのプロパティまでreadonlyにはしないことに起因します。

const assertionはすべてのプロパティを固定する

as constを付けます。

ts
const america = {
name: "North American Continent",
canada: {
name: "Republic of Canada",
capitalCity: "Ottawa",
},
us: {
name: "United States of America",
capitalCity: "Washington, D.C.",
},
mexico: {
name: "United Mexican States",
capitalCity: "Mexico City",
},
} as const;
ts
const america = {
name: "North American Continent",
canada: {
name: "Republic of Canada",
capitalCity: "Ottawa",
},
us: {
name: "United States of America",
capitalCity: "Washington, D.C.",
},
mexico: {
name: "United Mexican States",
capitalCity: "Mexico City",
},
} as const;

readonlyと同様にトップレベルのプロパティへの代入はできません。

ts
america.name = "African Continent";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.
america.canada = {
Cannot assign to 'canada' because it is a read-only property.2540Cannot assign to 'canada' because it is a read-only property.
name: "Republic of Côte d'Ivoire",
capitalCity: "Yamoussoukro",
};
ts
america.name = "African Continent";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.
america.canada = {
Cannot assign to 'canada' because it is a read-only property.2540Cannot assign to 'canada' because it is a read-only property.
name: "Republic of Côte d'Ivoire",
capitalCity: "Yamoussoukro",
};

これだけではなくオブジェクトが持つプロパティも同様にreadonlyにしてくれます。

ts
america.canada.name = "Republic of Côte d'Ivoire";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.
america.canada.capitalCity = "Yamoussoukro";
Cannot assign to 'capitalCity' because it is a read-only property.2540Cannot assign to 'capitalCity' because it is a read-only property.
ts
america.canada.name = "Republic of Côte d'Ivoire";
Cannot assign to 'name' because it is a read-only property.2540Cannot assign to 'name' because it is a read-only property.
america.canada.capitalCity = "Yamoussoukro";
Cannot assign to 'capitalCity' because it is a read-only property.2540Cannot assign to 'capitalCity' because it is a read-only property.

関連情報

📄️ 型アサーション「as」

TypeScriptには、型推論を上書きする機能があります。その機能を型アサーション(type assertion)と言います。

📄️ オブジェクト型のreadonlyプロパティ

TypeScriptでは、オブジェクトのプロパティを読み取り専用にすることができます。読み取り専用にしたいプロパティにはreadonly修飾子をつけます。読み取り専用のプロパティに値を代入しようとすると、TypeScriptコンパイラーが代入不可の旨を警告するようになります。