Skip to content

as const の使い方とユースケース

TypeScriptのas constは、リテラル型の推論をより厳密にする「constアサーション」です。これにより、変数が読み取り専用(readonly)になり、型の絞り込みが行われます。

問題: リテラル型の拡大を防ぐ

as constを使用しない場合、TypeScriptはリテラル値の型をより広範な型に拡大します:

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は可能な限り具体的な型を推論します:

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が重要な役割を果たしています:

typescript
// 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を使用すると、すべてのプロパティが読み取り専用になります:

typescript
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. リテラル型の保持

文字列リテラルが文字列型に拡大されるのを防ぎます:

typescript
// ユニオン型の例
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. タプル型の推論

配列を正確な長さと型のタプルとして推論します:

typescript
// 通常の配列推論
const pair = [1, "hello"]; // 型: (string | number)[]

// as const使用時
const pairConst = [1, "hello"] as const; // 型: readonly [1, "hello"]

実践的なユースケース

設定オブジェクトの定義

typescript
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;

// すべてのプロパティが読み取り専用で安全に使用可能

定数値の定義

typescript
// 従来の方法
const COLORS = {
  RED: "#FF0000",
  GREEN: "#00FF00",
  BLUE: "#0000FF"
} as const;

// キーも値も完全な型安全性
const redColor: "#FF0000" = COLORS.RED;

関数の戻り値の型推論

typescript
function createPoint(x: number, y: number) {
  return [x, y] as const;
}

// 戻り値の型: readonly [number, number]
const point = createPoint(10, 20);

注意点

WARNING

as constはコンパイル時のみの機能であり、実行時には影響しません。実行時にも不変性を確保する必要がある場合は、Object.freeze()などの方法を併用する必要があります。

typescript
// 実行時にも不変にする場合
const immutableConfig = Object.freeze({
  value: "cannot be changed"
} as const);

まとめ

as constは以下の場合に特に有用です:

  • リテラル型を正確に保持したい場合
  • 読み取り専用のデータ構造を定義したい場合
  • タプル型として配列を扱いたい場合
  • 設定オブジェクトや定数値を安全に定義したい場合

TypeScriptの型システムを最大限に活用するために、as constを適切に使用することで、より安全で意図が明確なコードを書くことができます。