はじめに
この記事では、TypeScriptにおける as const
の概要や使いどころ、注意点などについてサンプルコードを交えながらまとめます。
as const
とは?
TypeScriptの as const
は、リテラル型をそのまま保持するための型アサーション(型の断定)です。
通常、配列やオブジェクトを定義すると、その中身はより広い型に推論されますが、as const
を使うことで 中身の型をリテラルに固定し、さらに readonly にする ことができます。
▼ 例:配列の場合
const arr = [1, 2, 3];
// 推論: number[]
const fixedArr = [1, 2, 3] as const;
// 推論: readonly [1, 2, 3]
▼ 例:オブジェクトの場合
const obj = { role: "admin" };
// 推論: { role: string }
const fixedObj = { role: "admin" } as const;
// 推論: { readonly role: "admin" }
主な用途
固定された選択肢を型として定義したいときに非常に便利です。
例えば、色を選ぶフォームの選択肢や、APIが "red" | "green" | "blue"
のような固定値(enum的な値)を返す場合に便利です。
const colors = ["red", "green", "blue"] as const;
// 推論: readonly ["red", "green", "blue"]
type Color = typeof colors[number];
// Color型: "red" | "green" | "blue"
この Color
型を使えば、UIでの選択やバリデーション、APIとの整合性を型で保証できます。
▼ 使用例1: セレクトボックスの選択値に使う
function onSelectColor(color: Color) {
console.log(`選ばれた色は ${color} です`);
}
onSelectColor("red"); // ✅ OK
onSelectColor("yellow"); // ❌ エラー: 型 '"yellow"' を型 'Color' に割り当てることはできません。
▼ 使用例2: APIから受け取った色が有効か判定する
function isValidColor(value: string): value is Color {
return colors.includes(value as Color);
}
const fromApi = "green";
if (isValidColor(fromApi)) {
// fromApi の型はここで Color に絞られる
console.log(`APIから受け取った色: ${fromApi}`);
} else {
console.error("不正な色の値を受信しました");
}
typeof colors[number]
の [number]
について
-
typeof colors
-
colors
配列の型そのものを取得 -
as const
を使用しているため、TypeScript はcolors
をreadonly ["red", "green", "blue"]
という固定されたタプルとして推論
-
-
[number]
- 配列やタプルの型に対して
[number]
をつける - 配列やタプルを数値のインデックス(例:
colors[0]
、colors[1]
)でアクセスした場合に返されるすべての要素の型を結合したユニオンを作成
- 配列やタプルの型に対して
[number]
がないと、typeof colors
は readonly ["red", "green", "blue"]
となり、これは配列そのものの型です。
[number]
を加えることで、TypeScript は「colors
配列に含まれる可能性のあるすべての要素の型」を抽出し、結果として "red" | "green" | "blue"
というユニオン型を生成します。これにより、Color
型は「"red"、"green"、"blue"
のいずれかの文字列」を表現できるようになります。
注意点
as const
を使うと、配列やオブジェクトのプロパティは自動的に readonly
になります。
const list = [1, 2, 3] as const;
list.push(4); // ❌ エラー: Property 'push' does not exist on type 'readonly [1, 2, 3]'
そのため、ミューテート(変更)する前提のデータには使えません。
Tips
as const
に関する Tips を紹介します。
1. 毎回 as const
を書くのが面倒? → const アサーションヘルパーの活用
as const
は便利ですが、使うたびに毎回手で書くのは少し煩わしいと感じるかもしれません。
特にユニオン型を作るための配列を何度も定義するようなケースでは、次のように繰り返し as const
を書くことになります。
const colors = ["red", "green", "blue"] as const;
const sizes = ["small", "medium", "large"] as const;
const roles = ["admin", "user", "guest"] as const;
このようなパターンが増えてくると、毎回 as const
を書く手間や統一されていない記述が気になってきます。
そんなときは以下のようなユーティリティ関数を 1 つ定義しておくと、定数配列を簡潔かつ一貫性のある方法で定義できます。
// ユニオン型を得るための定数配列を定義するヘルパー関数
const defineConstArray = <T extends readonly string[]>(arr: T) => arr;
これを使えば、as const
を意識せずに済みます。
const categories = defineConstArray(["news", "event", "release"]);
// 推論: readonly ["news", "event", "release"]
type Category = typeof categories[number];
// 型: "news" | "event" | "release"
2. バリデーションライブラリとの連携
as const
を使って定義したユニオン型を、Zodなどのバリデーションライブラリでも活用できます。
as const
を使えば、Zodのスキーマと型を一箇所で定義できます。
import { z } from "zod";
// まず定数配列を定義
const colors = ["red", "green", "blue"] as const;
// スキーマは配列から直接生成できる
const ColorSchema = z.enum(colors);
// 型もスキーマから取得可能(または typeof colors[number] でもOK)
type Color = z.infer<typeof ColorSchema>;
z.enum(colors)
は、readonly ["red", "green", "blue"]
の配列を受け取って Zod の enum スキーマを作ります。型 Color
は "red" | "green" | "blue"
として推論され、フォーム入力や API レスポンスの型としても活用できます。
こうすることで、定義の重複を避けつつ、型とバリデーションの整合性が取れるようになります。
まとめ
as const
は、TypeScriptでリテラル型を固定し、readonly
な定数として扱うための便利な機能です。配列やオブジェクトに使うことで、ユニオン型の生成や型安全なバリデーションが可能になり、フォーム選択肢やAPIレスポンスの扱いを強力にサポートします。
as const
を毎回書くのが煩雑な場合はユーティリティ関数で簡略化でき、Zodと組み合わせればスキーマ定義と型定義を一元化することも可能です。型の整合性を保ちながら効率的にコーディングしたいときに活用したいテクニックです。
参考
関連記事