as const
の使い方とユースケース
TypeScriptのas const
は、リテラル型の推論をより厳密にする「constアサーション」です。これにより、変数が読み取り専用(readonly)になり、型の絞り込みが行われます。
問題: リテラル型の拡大を防ぐ
as const
を使用しない場合、TypeScriptはリテラル値の型をより広範な型に拡大します:
// 型: string
const status = "success";
// 型: number[]
const numbers = [1, 2, 3];
// 型: { name: string, age: number }
const user = { name: "John", age: 30 };
これにより、型安全性が損なわれる場合があります。
解決策: as const
によるconstアサーション
as const
を使用すると、TypeScriptは可能な限り具体的な型を推論します:
// 型: "success"
const status = "success" as const;
// 型: readonly [1, 2, 3]
const numbers = [1, 2, 3] as const;
// 型: { readonly name: "John", readonly age: 30 }
const user = { name: "John", age: 30 } as const;
配列とタプルでの使用例
元の質問のコード例では、as const
が重要な役割を果たしています:
// as constなし - エラー発生
const args = [8, 5]; // 型: number[]
const angle = Math.atan2(...args); // ❌ エラー: 2つの引数が必要だが、0個以上の引数が渡されている
// as constあり - 正常動作
const args = [8, 5] as const; // 型: readonly [8, 5]
const angle = Math.atan2(...args); // ✅ OK
INFO
Math.atan2()
は正確に2つの数値引数を必要とします。as const
により、配列が正確に2要素のタプルであることが保証されます。
as const
の主な特徴
1. 読み取り専用プロパティ
オブジェクトにas const
を使用すると、すべてのプロパティが読み取り専用になります:
const config = {
port: 3000,
name: "my-app",
settings: {
debug: true,
version: "1.0.0"
}
} as const;
// 以下の操作はすべてコンパイルエラーになります:
config.port = 4000; // ❌
config.settings.debug = false; // ❌
config.settings.newProp = "value"; // ❌
2. リテラル型の保持
文字列リテラルが文字列型に拡大されるのを防ぎます:
// ユニオン型の例
type Status = "success" | "error";
function handleStatus(status: Status) {
console.log(status);
}
const status = "success"; // 型: string
handleStatus(status); // ❌ エラー: string型はStatus型に代入不可
const statusConst = "success" as const; // 型: "success"
handleStatus(statusConst); // ✅ OK
3. タプル型の推論
配列を正確な長さと型のタプルとして推論します:
// 通常の配列推論
const pair = [1, "hello"]; // 型: (string | number)[]
// as const使用時
const pairConst = [1, "hello"] as const; // 型: readonly [1, "hello"]
実践的なユースケース
設定オブジェクトの定義
const APP_CONFIG = {
version: "1.0.0",
api: {
baseUrl: "https://api.example.com",
endpoints: ["/users", "/posts"] as const
},
features: {
darkMode: true,
analytics: false
}
} as const;
// すべてのプロパティが読み取り専用で安全に使用可能
定数値の定義
// 従来の方法
const COLORS = {
RED: "#FF0000",
GREEN: "#00FF00",
BLUE: "#0000FF"
} as const;
// キーも値も完全な型安全性
const redColor: "#FF0000" = COLORS.RED;
関数の戻り値の型推論
function createPoint(x: number, y: number) {
return [x, y] as const;
}
// 戻り値の型: readonly [number, number]
const point = createPoint(10, 20);
注意点
WARNING
as const
はコンパイル時のみの機能であり、実行時には影響しません。実行時にも不変性を確保する必要がある場合は、Object.freeze()などの方法を併用する必要があります。
// 実行時にも不変にする場合
const immutableConfig = Object.freeze({
value: "cannot be changed"
} as const);
まとめ
as const
は以下の場合に特に有用です:
- リテラル型を正確に保持したい場合
- 読み取り専用のデータ構造を定義したい場合
- タプル型として配列を扱いたい場合
- 設定オブジェクトや定数値を安全に定義したい場合
TypeScriptの型システムを最大限に活用するために、as const
を適切に使用することで、より安全で意図が明確なコードを書くことができます。