普段はフロントエンドエンジニアとしてJavaScript/TypeScript/Aangular/GraphQLを
メインに開発業務を行なっています。
今回は久々にTypeScriptをテーマにした記事を書いていきたいと思います。「const assertion」を結構使用してますが、readonlyとどう違うのか疑問に思ったので調べてみました。
const assertion(as const)とは
const assertionとは全ての値を読み取り専用及び変更不可にするアサーションです。記載方法はオブジェクトの末尾にas constを記述すことで、プロパティをreadonlyで指定した場合と同等の扱いにすることができます。
const sampleObject = { a: 'Foo', b: 'Apple', c: 42, d: 50 } as const sampleObject.a = 'Bar' // Cannot assign to 'a' because it is a read-only property.
as constをオブジェクトに指定した場合、オブジェクトに別の値を代入すると、エラーが発生して怒られる為、代入することはできません。もちろんas constを記載しない場合は、通常通り値を代入することが出来ます。
const sampleObject = { a: 'Foo', b: 'Apple', c: 42, d: 50 } as const sampleObject.a = 'Bar'
またas constの他の特徴として、Literal TypesがWideningされないこともあげられます。

Wideningは型が自動で拡張するTypeScriptの機能のことを指します。
constやletで宣言したLiteralTypesの変数に、オブジェクトのプロパティとした時にWideningが発生して予期せぬ挙動が引き起こされてしまいます。
例えば、message変数にHello worldを宣言したとします。
const message = 'hello world';
messageをオブジェクトのプロパティとして代入した場合、型が自動で拡張して値が変わってしまいます。
const message = 'hello world'; const test = { message }; console.log(test) // hello world test.message = 'Second world'; console.log(test.message); // Second world
as constを付け加えることで、このLiteral TypesがWideningされるのを防ぐことができます。
const message = 'hello world' as const; const test = { message }; test.message = 'Second world'; // Type '"Second world"' is not assignable to type '"hello world"'.
「readonly」と「const assertion」の違い
「readonly」と「const assertion」は記載することで両方とも、値を変更することが出来なくなる特徴があります。
主な違いとしては、const assertionはオプジェクト全体に宣言する事になり、全てのプロパティが対象なりますが、readonlyは必要なプロパティのみつけることが出来るということです。
type Continent = { readonly name: string; readonly canada: Country; readonly america: Country; readonly mexico: Country; };
readonlyが記載されたプロパティがオブジェクトまでである為、そのオブジェクトのプロパティにまでreadonlyにすることはできません。
type Country = { name: string; capitalCity: string; }; type Continent = { readonly name: string; readonly canada: Country; readonly america: Country; readonly mexico: Country; }; const america: Continent = { name: "North American Continent", canada: { name: "Republic of Canada", capitalCity: "Ottawa", }, america: { name: "United States of America", capitalCity: "Washington, D.C.", }, mexico: { name: "United Mexican States", capitalCity: "Mexico City", }, };
上記の通り記載した場合、そのオブジェクトのプロパティまでreadonlyが起因せず、値を代入することができます。
america.canada.name = "Republic of Côte d'Ivoire"; america.canada.capitalCity = "Yamoussoukro";
一方で、const assertionの場合は再起的にreadonlyとすることが出来るため、例えば以下のように値を代入することが出来ません。
america.name = "African Continent"; // Cannot assign to 'name' because it is a read-only property. america.canada = { name: "Republic of Côte d'Ivoire", capitalCity: "Yamoussoukro", }; // Cannot assign to 'canada' because it is a read-only property.
また先ほど記述した、Literal TypesのがWideningされるのを防ぐのもconst assertionとreadonlyの違いとなります。
本日はここまでとなります。
最後までお読み下さりありがとうございました。
■ 参考文献