【TypeScript】 `const enum` について

## はじめに
`const enum`は、TypeScriptで提供される最適化された列挙型です。通常の`enum`とは異なり、`const enum`はコンパイル時にインライン展開され、より効率的なコードを生成します。

## `const enum`の基本的な使い方

`const enum`は通常の`enum`と同じように定義できます。ただし、`const`キーワードを追加します。

```typescript
const enum Direction {
    Up,
    Down,
    Left,
    Right
}

let direction: Direction = Direction.Up;
console.log(direction); // 0
```

このコードは、コンパイル時に以下のように変換されます。

```javascript
let direction = 0 /* Direction.Up */;
console.log(direction); // 0
```

このように、`const enum`のメンバーはコンパイル時にインライン展開され、実行時に追加のオブジェクト参照を避けることができます。

## 利点

### 1. 高速な実行時パフォーマンス

`const enum`は、コンパイル時にインライン展開されるため、実行時に追加のオブジェクト参照が発生せず、高速に動作します。

### 2. より少ないコード生成

`const enum`は、コンパイル後のコードサイズを小さく保ちます。通常の`enum`では、列挙型オブジェクトが生成されますが、`const enum`ではこれが不要です。

## 使用例

### 数値 `const enum`

```typescript
const enum Direction {
    Up,
    Down,
    Left,
    Right
}

function move(direction: Direction) {
    switch (direction) {
        case Direction.Up:
            console.log("Moving up!");
            break;
        case Direction.Down:
            console.log("Moving down!");
            break;
        case Direction.Left:
            console.log("Moving left!");
            break;
        case Direction.Right:
            console.log("Moving right!");
            break;
    }
}

move(Direction.Up);   // "Moving up!"
move(Direction.Right); // "Moving right!"
```

このコードは以下のようにコンパイルされます。

```javascript
function move(direction) {
    switch (direction) {
        case 0 /* Direction.Up */:
            console.log("Moving up!");
            break;
        case 1 /* Direction.Down */:
            console.log("Moving down!");
            break;
        case 2 /* Direction.Left */:
            console.log("Moving left!");
            break;
        case 3 /* Direction.Right */:
            console.log("Moving right!");
            break;
    }
}

move(0 /* Direction.Up */);   // "Moving up!"
move(3 /* Direction.Right */); // "Moving right!"
```

### 文字列 `const enum`

文字列`const enum`もサポートされています。

```typescript
const enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT"
}

function move(direction: Direction) {
    switch (direction) {
        case Direction.Up:
            console.log("Moving up!");
            break;
        case Direction.Down:
            console.log("Moving down!");
            break;
        case Direction.Left:
            console.log("Moving left!");
            break;
        case Direction.Right:
            console.log("Moving right!");
            break;
    }
}

move(Direction.Up);   // "Moving up!"
move(Direction.Right); // "Moving right!"
```

このコードは以下のようにコンパイルされます。

```javascript
function move(direction) {
    switch (direction) {
        case "UP" /* Direction.Up */:
            console.log("Moving up!");
            break;
        case "DOWN" /* Direction.Down */:
            console.log("Moving down!");
            break;
        case "LEFT" /* Direction.Left */:
            console.log("Moving left!");
            break;
        case "RIGHT" /* Direction.Right */:
            console.log("Moving right!");
            break;
    }
}

move("UP" /* Direction.Up */);   // "Moving up!"
move("RIGHT" /* Direction.Right */); // "Moving right!"
```

## 注意点

### コンパイルオプション

`const enum`は、`preserveConstEnums`コンパイルオプションを有効にしている場合を除き、コンパイル時に削除されます。このオプションを有効にすると、`const enum`も通常の`enum`と同様に扱われ、インライン展開されなくなります。

`tsconfig.json`の例：

```json
{
  "compilerOptions": {
    "preserveConstEnums": false
  }
}
```

### エラー回避

`const enum`のメンバーはインライン展開されるため、エラーをキャッチするのが難しくなることがあります。特に、定数値が変更された場合や、参照される`const enum`が削除された場合です。従って、`const enum`を使用する際には、定義の変更に注意が必要です。

## まとめ

`const enum`は、TypeScriptで効率的な列挙型を提供する強力なツールです。インライン展開されるため、実行時のパフォーマンスが向上し、生成されるコードも少なくなります。ただし、`const enum`を使用する際には、コンパイルオプションや定義の変更に注意が必要です。