【ITニュース解説】Const Assertions en TypeScript 🤔
2025年09月03日に「Dev.to」が公開したITニュース「Const Assertions en TypeScript 🤔」について初心者にもわかりやすいように丁寧に解説しています。
ITニュース概要
TypeScriptの`as const`は、変数や配列、オブジェクトの型を、その最も具体的な値のリテラル型に固定する機能だ。これにより、データは読み取り専用となり、後から内容を変更できなくなる。厳密な型チェックを可能にし、コードの堅牢性向上に貢献する。
ITニュース解説
TypeScriptは、JavaScriptに型の概念を導入することで、プログラムの記述をより正確にし、長期的なメンテナンス性を向上させるためのプログラミング言語である。変数にデータ型を割り当てることで、想定外のデータが代入されることによるバグを防ぎ、開発の早い段階でエラーを発見しやすくする。
しかし、TypeScriptが自動的に推論する型や、開発者が宣言する型が、必ずしもプログラムの厳密な意図を完全に捉えきれない場合がある。このような状況で用いられるのが「型アサーション」だ。型アサーションとは、開発者がTypeScriptに対して「この変数は、私が指定するこの型であると断言する」と伝えるための機能である。これは、あるデータ型を別のデータ型に強制的に変換する「型キャスト」のようなものと考えると理解しやすい。例えば、const message = "こんにちは" as string; と書くことで、message が文字列型であることを明示的にTypeScriptに伝えることができる。配列に対しても const names = ["太郎", "花子"] as string[]; のように、要素が文字列の配列であることを断言したり、names as [string, string]; のように、二つの文字列からなる固定長のタプルであることを指定したりすることも可能である。
この型アサーションの特別な形態として、「const assertion(コンスト・アサーション)」が存在する。これは as const というキーワードを用いて記述される。const assertionは、TypeScriptが変数の型を推論する際に、その変数の値を「可能な限り最も限定的で具体的な型(リテラル型)」として扱い、同時にその変数を「読み取り専用(readonly)」にするための強力な指示となる。
const assertionの具体的な動作を例で見てみよう。ある文字列の最初の文字とその長さを返す関数 function processText(text: string) { return [text[0], text.length]; } を考える。この関数が processText("TypeScript"); と呼び出された場合、TypeScriptは戻り値の型を (string | number)[]、つまり文字列または数値を含む可能性のある配列型と推論する。この型では、返された配列に後から result.push("追加"); のように、他の文字列や数値を自由に追加できてしまう。
しかし、この関数に as const を適用するとどうなるだろうか。function processText(text: string) { return [text[0], text.length] as const; } と記述すると、TypeScriptは戻り値の型を readonly [string, number] と推論する。これは、「最初の要素が文字列型、二番目の要素が数値型であり、要素数が2で固定された読み取り専用のタプル」を意味する。この型が適用されると、result.push("追加"); のような要素を追加する操作はコンパイルエラーとなり、許されなくなる。これは、関数が常に最初の文字と長さの二つの要素だけを返し、それ以外の状態にはならないという、プログラムの厳密な意図をTypeScriptに伝えることができることを示している。
const assertionの主なユースケースは三つある。
一つ目は「プリミティブ型」に対する適用である。プリミティブ型とは、文字列、数値、真偽値といった基本的なデータ型のことだ。通常、const fruit = "りんご"; と書くと、fruit の型は一般的な string と推論される。しかし、const fruit = "りんご" as const; と記述すると、fruit の型は string ではなく、"りんご" という「リテラル文字列型」になる。これは、fruit が常にこの特定の値 "りんご" であることをTypeScriptに明示的に伝えるもので、より厳密な型チェックが可能になる。例えば、ユーザーの権限タイプを "admin" または "user" に限定したい場合、{ role: "admin" } と書くと role の型は string と推論されてしまい、"guest" のような想定外の文字列も許容されてしまう可能性がある。しかし、{ role: "admin" as const } とすれば、role の型は "admin" というリテラル型となり、厳密な型チェックが機能するようになる。
二つ目は「配列」に対する適用である。配列に as const を適用すると、その配列は「読み取り専用のタプル」に変換される。タプルとは、要素の数とそれぞれの要素の型が固定された配列のようなデータ構造だ。例えば、let numbers = [10, 20, 30] as const; と記述すると、numbers の型は readonly [10, 20, 30] となる。この型が適用された配列は、要素の追加(numbers.push(40);)や、既存の要素の変更(numbers[0] = 50;)といった操作がすべてコンパイルエラーとなる。これは、配列の内容が初期化された時点から一切変更されないことを保証したい場合に非常に有効な手段である。
三つ目は「オブジェクト」に対する適用である。オブジェクト全体に as const を適用すると、そのオブジェクトのすべてのプロパティが「読み取り専用」になり、さらにその値が「最も限定的なリテラル型」として推論されるようになる。例えば、const config = { api_key: "abcde", version: 1 } as const; と書くと、config.api_key は "abcde" というリテラル文字列型に、config.version は 1 というリテラル数値型になる。そして、これらのプロパティはすべて読み取り専用となるため、config.version = 2; のようなプロパティ値の変更は許可されなくなる。これは、アプリケーションの設定オブジェクトや、変更されるべきではない固定データを定義する際に、予期せぬ変更を防ぎ、型安全性を高めるのに役立つ。もしオブジェクト全体ではなく、特定のプロパティだけをリテラル型にしたい場合は、そのプロパティの値に直接 as const を適用することもできる。const preferences = { mode: "dark" as const }; のように記述する。
const assertionは、このようにプログラム内で扱うデータの不変性を保証し、TypeScriptの型推論をより厳密に制御するための非常に強力な機能である。as const を使うことで、開発者はTypeScriptにコードの意図をより正確に伝え、コンパイル時に潜在的なエラーを発見しやすくすることができる。この機能はTypeScript固有のものであり、最終的にJavaScriptにコンパイルされた際には、その型に関する情報は削除され、純粋なJavaScriptのコードになる。しかし、開発段階での型安全性を高める上で、その価値は非常に大きい。const assertionは、変数を最も具体的なリテラル型にし、さらに読み取り専用にする、というシンプルな原則に基づいている。