const は「値」と「型」をその場で固定する宣言
const は「再代入できない変数」を宣言するキーワードですが、TypeScriptでは型の固定のされ方にも特徴があります。const で宣言した瞬間に、「この変数にはこの値(=この型)しか来ない」という前提がかなり強くなります。
const name = "Taro";
TypeScriptこの1行で、
「name は再代入できない」
「name は文字列で、しかも "Taro" という値で固定されている」
という情報を TypeScript は持ちます(リテラル型として扱われるイメージ)。
let と違って、「あとで別の値が入るかもしれない」という可能性がないので、コンパイラはより“固い”型として扱えるわけです。
let と const の型推論の違い
let は「将来変わるかも」を前提にした型
let の場合、初期値から型は推論されますが、「将来別の値が入るかもしれない」という前提で、少し広めに扱われます。
let color = "red"; // 型は string と推論される
color = "blue"; // OK
color = "green"; // OK
// color = 123; // エラー(number はダメ)
TypeScript"red" という値から始まっていますが、「将来 "blue" や "green" になるかもしれない」ので、型としては「string 全体」と見なされます。
const は「この値そのもの」を型として扱える
一方 const の場合、値が変わらないので、もっと狭い型——リテラル型として扱えます。
const color = "red"; // 型は "red" という文字列リテラル型
// color = "blue"; // そもそも再代入がエラー
TypeScriptここでのポイントは、「color の型は string ではなく "red"」ということです。
つまり、「color は ‘red’ 以外になり得ない」という情報を、型レベルで持てるようになります。
この「リテラル型として固定される」という性質が、const 時の型の固定の一番おいしいところです。
const とオブジェクト・配列の型の固定
参照は固定されるが、中身は変えられる
まず大事な前提として、const は「再代入を禁止する」だけであって、「中身の変更まで禁止する」わけではありません。
const user = {
name: "Taro",
age: 20
};
user.name = "Hanako"; // OK(プロパティの変更)
// user = { name: "Jiro", age: 30 }; // エラー(再代入)
TypeScriptuser という「箱」がどのオブジェクトを指しているかは固定されますが、そのオブジェクトのプロパティは変更できます。
型としては、user の型は { name: string; age: number } のように推論され、そのプロパティに対して型チェックが効き続けます。
as const で「中身まで完全固定」する
「このオブジェクトの中身も含めて、全部リテラルとして固定したい」というときは、as const を使います。
const user = {
name: "Taro",
age: 20
} as const;
TypeScriptこうすると、型は次のようなイメージになります。
{
readonly name: "Taro";
readonly age: 20;
}
TypeScriptプロパティも readonly になり、値も "Taro" と 20 に固定されます。
設定値や定数テーブルのように、「絶対に変わらない前提のデータ」を表現するときにとても強力です。
const で型を固定することのメリット
「変わらない前提」を型に刻める
const を使う一番のメリットは、「この値は変わらない」という前提を、人間にもコンパイラにも伝えられることです。
const TAX_RATE = 0.1;
TypeScriptこの1行で、
「TAX_RATE は number で、0.1 という値で固定」
「途中で誰かが書き換えることはできない」
という保証が得られます。
もし let TAX_RATE = 0.1; と書いていたら、どこかで TAX_RATE = 0.08; と上書きされる可能性があります。const にしておけば、そういうバグはコンパイル時に止められます。
リテラル型として扱えることで、より強い型チェックができる
const で固定されたリテラル型は、ユニオン型などと組み合わせるとさらに威力を発揮します。
const THEME_LIGHT = "light" as const;
const THEME_DARK = "dark" as const;
type Theme = typeof THEME_LIGHT | typeof THEME_DARK;
let theme: Theme = THEME_LIGHT; // "light" | "dark" のどちらか
// theme = "blue"; // エラー
TypeScriptここでは、"light" と "dark" という具体的な値を型として扱い、「この2つ以外は許さない」というルールを作っています。const で値を固定しているからこそ、こういう「値レベルの型」を安全に使えるわけです。
初心者がまず意識すべき const 時の型の固定の感覚
難しいことを抜きにして、まずはこう捉えておくといいです。
const で宣言した瞬間、その変数は「値も型もその場で固まる」。
「変わらない前提のもの」は、必ず const にする。let は「本当に変える必要があるときだけ」にする。
この感覚が身につくと、
「どこが動く部分で、どこが固定の前提なのか」
がコードから自然と読み取れるようになります。
そして TypeScript は、その「前提」を型として理解し、再代入の禁止やリテラル型としての扱いを通じて、あなたの意図を守ってくれます。const は、ただの「再代入禁止」ではなく、「設計の意図を型に刻むための道具」だと思って使ってみてほしい。
