【Typescript】as const って結局何?調べたことをまとめてみた
✍️ はじめに
実務で 型アサーション= as const
を使うことはよくあります。実務でも as const
を使用しているコードをよく見たり、自分も使っていましたが今まで深く考えずに使っていました。
最近、『【初学者向け】具体例で学ぶTypeScript練習問題集』の問題を解いているときに、以下の問題に出会いました:
【Lv.3】オブジェクトのインデックス
そのときふと、「そもそも as const
って何をしてるんだっけ?」「なぜ付けたほうがいいの?」と疑問に思いました。
本記事では as const
の役割と、通常の型推論との違いを整理していきます。
🔍 as const の効果とは?
const statusColors = {
success: "green",
error: "red",
warning: "yellow"
}; // 通常の型推論(string型)
この場合、TypeScript は以下のように推論します:
const statusColors: {
success: string;
error: string;
warning: string;
}
一見問題なさそうですが、statusColors.success
は "green" であることが明らかなのに、型としては string
になってしまっています。
ここで as const
を付けると、型は次のように変わります:
const statusColors = {
success: "green",
error: "red",
warning: "yellow"
} as const; // リテラル型 + readonly になる
const statusColors: {
readonly success: "green";
readonly error: "red";
readonly warning: "yellow";
}
💡 何が変わったのか?
- 値の型が
string
ではなく、"green" や "red" といったリテラル型に変わった - 各プロパティに
readonly
が付き、変更不可(イミュータブル)になる
この違いにより、TypeScript がより厳密に型を扱えるようになります。
特に注目したいのは、値がリテラル型になるという点です。
今までは readonly
によって変更を防げるというメリットばかり意識しがちでしたが、
リテラル型になることで Union 型として抽出できるようになり、型安全な処理がしやすくなります。
これは実務でのバリデーションやキーの制約、表示の切り替えなどにも活用できる大きな利点です。
🎨 具体例:ステータスごとの色マッピング
ここでは、ステータスに対応する色を定義したオブジェクトを例にとります。
const statusColors = {
success: "green",
error: "red",
warning: "yellow",
} as const;
// キーの型を抽出
type Status = keyof typeof statusColors; // "success" | "error" | "warning"
// 値の型を抽出
type Color = typeof statusColors[Status]; // "green" | "red" | "yellow"
このように as const
を使うことで、オブジェクトの値を具体的なリテラル型として扱えるため、Union 型として抽出することが可能になります。
⚠️ as const を付ければ何でも安全なのか?注意すべきケースを考える
ここまで as const
のメリットについて考えてきました。
ただし、注意すべき点がないのかも検討する必要があります。
as const
を付けたからといって、すべてのバグを防げるわけではありません。
型が厳密になりすぎて逆に扱いにくくなることもあるので、状況に応じて使い分ける必要があります。
例えば次のようなケースを考えてみましょう:
const directions = ["up", "down"] as const;
function move(dir: string) {
console.log(dir);
}
move(directions[0]); // 問題なく動作します
この例では、directions[0]
の型は "up"
というリテラル型になりますが、リテラル型は対応する一般的な型(この場合は string
)に自動的に割り当て可能です。つまり、リテラル型 "up"
は string
型に問題なく割り当てられます。
一方、逆のケースでは問題が発生します:
const directions = ["up", "down"] as const;
type Direction = typeof directions[number]; // "up" | "down"
function moveStrict(dir: Direction) {
console.log(dir);
}
const someString: string = "up";
moveStrict(someString); // エラー: 型 'string' を型 '"up" | "down"' に割り当てることはできません
この場合、someString
は一般的な string
型であり、実行時に "up"
や "down"
以外の値を持つ可能性があるため、より具体的な Direction
型に割り当てることはできません。
📝 まとめ
-
as const
は値をリテラル型として固定し、かつreadonly
を付けてくれる - 型推論が「string」や「number」などの柔らかい型になるのを防ぎたいときに使う
- Union 型の抽出や、型安全なマッピングにとても便利
何気なく使っていたas const
ですが、その意図を知ることで TypeScript をより強力に、安全に活用できるようになります。
🙇♂️ 参考記事
本記事は以下のZenn記事から多くの気づきを得て執筆しました。とても勉強になりました。ありがとうございます!
Discussion