TypeScriptの基礎 - 列挙型と定数

提供: MochiuWiki : SUSE, EC, PCB

2026年2月24日 (火) 03:03時点におけるWiki (トーク | 投稿記録)による版 (ページの作成:「== 概要 == TypeScriptの列挙型 (enum) は、関連する定数値に名前を付けてグループ化するための機能である。<br> <br> enumには数値enum、文字列enum、const enumの3種類があり、それぞれ異なるコンパイル結果と用途を持つ。<br> また、TypeScript独自の機能である <code>as const</code> アサーションを使用することで、enumに相当するパターンをより軽量に実現することも…」)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

概要

TypeScriptの列挙型 (enum) は、関連する定数値に名前を付けてグループ化するための機能である。

enumには数値enum、文字列enum、const enumの3種類があり、それぞれ異なるコンパイル結果と用途を持つ。
また、TypeScript独自の機能である as const アサーションを使用することで、enumに相当するパターンをより軽量に実現することもできる。

TypeScript 5.0以降では、全てのenumがユニオンenumとして統一的に扱われるようになり、型安全性が大幅に向上した。
具体的には、enum型の変数に対してenum外の値を代入した場合にエラーが発生するようになった。
また、TypeScript 5.4ではenumメンバーとしての NaN および Infinity の使用が禁止され、enum互換性チェックも厳格化された。

TypeScript 6.0ベータ以降もenumは引き続きサポートされているが、将来的なTypeScript 7.0 (Project Corsa、Go言語による書き直し) においても後方互換性が維持される予定である。

下表に、TypeScriptで利用可能なenum関連の種類と特徴を示す。

enumの種類と特徴
種類 逆マッピング コンパイル後のコード 主な用途
数値enum あり IIFEパターンのオブジェクト生成コード 内部フラグ、ビットマスク、順序付き定数
文字列enum なし IIFEパターンのオブジェクト生成コード APIレスポンス値、データベース値、可読性重視の定数
const enum なし インライン展開 (ランタイムコードなし) パフォーマンス最優先の定数
異種enum (Heterogeneous) 数値メンバーのみあり IIFEパターンのオブジェクト生成コード 非推奨
特別な理由がない限り使用しない。



数値enum

数値enumは、メンバーに数値を割り当てるenumである。
デフォルトでは0から始まり、後続のメンバーへ自動的にインクリメントされる。

基本的な構文

数値enumの基本構文を以下に示す。

 enum Direction {
    Up,     // 0
    Down,   // 1
    Left,   // 2
    Right   // 3
 }
 
 const move = Direction.Up;    // 0
 const name = Direction[0];    // "Up" (逆マッピング)


ビットマスクパターンを使用する例を以下に示す。
ビットシフト演算子を使用することで、フラグの組み合わせを表現できる。

 enum Permission {
    None    = 0,
    Read    = 1 << 0,                  // 1
    Write   = 1 << 1,                  // 2
    Execute = 1 << 2,                  // 4
    Admin   = Read | Write | Execute   // 7
 }
 
 const userPerm = Permission.Read | Permission.Write;  // 3
 const canRead  = (userPerm & Permission.Read) !== 0;  // true


自動インクリメントと明示的な値の指定

enumメンバーに明示的に値を指定することができる。
明示的に値を指定したメンバー以降は、そのメンバーの値から+1ずつ自動インクリメントされる。

 enum Direction {
    Up    = 1,   // 1 (明示的)
    Down,        // 2 (自動インクリメント)
    Left,        // 3 (自動インクリメント)
    Right        // 4 (自動インクリメント)
 }
 
 enum HttpStatus {
    OK                  = 200,
    Created             = 201,
    BadRequest          = 400,
    Unauthorized        = 401,
    NotFound            = 404,
    InternalServerError = 500
 }


数値enumの逆マッピング

数値enumは逆マッピングをサポートしており、値からメンバー名を取得できる。
これは、数値enumのコンパイル結果が双方向のマッピングを持つオブジェクトを生成するためである。

 enum Direction {
    Up = 1,
    Down,
    Left,
    Right
 }
 
 // 通常のマッピング (名前 -> 値)
 console.log(Direction.Up);     // 1
 
 // 逆マッピング (値 -> 名前)
 console.log(Direction[1]);     // "Up"
 console.log(Direction[2]);     // "Down"


コンパイル後のJavaScriptコードは、IIFEパターンで生成される。

 // コンパイル結果
 var Direction;
 (function (Direction) {
    Direction[Direction["Up"]    = 1] = "Up";
    Direction[Direction["Down"]  = 2] = "Down";
    Direction[Direction["Left"]  = 3] = "Left";
    Direction[Direction["Right"] = 4] = "Right";
 })(Direction || (Direction = {}));


TypeScript 5.0以降では、型安全性が向上し、enum型の変数にenum外の値を代入するとエラーになる。

 enum Status {
    Pending = 0,
    Active  = 1
 }
 
 function process(status: Status) {
    if (status === 99) {   // TypeScript 5.0以降: エラー
       console.log("Unknown");
    }
 }



文字列enum

文字列enumは、各メンバーに明示的に文字列値を指定するenumである。
APIレスポンスやデータベース値との対応が容易で、デバッグ時の可読性が高い。

基本的な構文

文字列enumでは、全てのメンバーに対して明示的に文字列値を指定する必要がある。

 enum Color {
    Red   = "RED",
    Green = "GREEN",
    Blue  = "BLUE"
 }
 
 enum Direction {
    Up    = "UP",
    Down  = "DOWN",
    Left  = "LEFT",
    Right = "RIGHT"
 }
 
 const color = Color.Red;  // "RED"
 console.log(color);       // "RED"


文字列enumの特徴

文字列enumと数値enumの主な違いを以下に示す。

  • 逆マッピング非対応
    文字列enumは逆マッピングを持たない。値からメンバー名を取得することはできない。
  • 自動インクリメント非対応
    全てのメンバーに対して明示的に値を指定する必要がある。
  • デバッグ時の可読性
    文字列値はそのまま表示されるため、数値と比べてデバッグ時に意味が分かりやすい。


文字列enumをAPIレスポンスの状態管理に使用する例を以下に示す。

 enum RequestState {
    Idle     = "IDLE",
    Loading  = "LOADING",
    Success  = "SUCCESS",
    Error    = "ERROR"
 }
 
 function handleState(state: RequestState): void {
    switch (state) {
       case RequestState.Loading:
          console.log("読み込み中...");
          break;
       case RequestState.Success:
          console.log("成功");
          break;
       case RequestState.Error:
          console.log("エラーが発生しました");
          break;
    }
 }



定数enum (const enum)

const enum は、コンパイル時にインライン展開されるenumである。
ランタイムにはenumオブジェクトが生成されないため、バンドルサイズを削減できる。

const enumの基本

const キーワードをenumの前に付けることで、const enumを定義できる。

 const enum Suit {
    Clubs    = 0,
    Diamonds = 1,
    Hearts   = 2,
    Spades   = 3
 }
 
 const hand1 = Suit.Diamonds;  // コンパイル結果 : var hand1 = 1;
 const hand2 = Suit.Hearts;    // コンパイル結果 : var hand2 = 2;


コンパイル結果の違い

通常のenumとconst enumのコンパイル結果の違いを以下に示す。

  • 通常のenumのコンパイル結果
     // ソースコード
     enum Suit { Clubs = 0, Diamonds = 1 }
     const value = Suit.Diamonds;
     
     // コンパイル結果 (IIFEパターンのオブジェクトが生成される)
     var Suit;
     (function (Suit) {
        Suit[Suit["Clubs"]    = 0] = "Clubs";
        Suit[Suit["Diamonds"] = 1] = "Diamonds";
     })(Suit || (Suit = {}));
     var value = Suit.Diamonds;   // 1
    

  • const enumのコンパイル結果
     // ソースコード
     const enum Suit { Clubs = 0, Diamonds = 1 }
     const value = Suit.Diamonds;
     
     // コンパイル結果 (enumオブジェクトは生成されず、値がインライン展開される)
     var value = 1;
    


const enumの制約と注意点

const enumには以下の制約がある。

const enumの制約一覧
制約 説明
逆マッピング非対応 const enumはインライン展開されるため、逆マッピングを使用できない。
computed memberの使用不可 const enumのメンバーには、リテラル値のみを使用できる。
計算式(computed member)は使用できない。
preserveConstEnums オプション tsconfig.jsonファイルpreserveConstEnums: true を設定することで、
const enumのランタイムコードを生成することができる。
型宣言ファイル(.d.ts)の制限 外部ライブラリの型宣言ファイルに定義されたconst enumを使用する場合、
isolatedModules オプションが有効な環境では問題が発生することがある。


 // computed memberは使用不可
 const enum Invalid {
    A = "hello".length  // エラー: const enumはcomputed memberを使用できない
 }
 
 // リテラル値のみ使用可能
 const enum Valid {
    A = 1,
    B = 2,
    C = A + B           // 他のconst enumメンバーの参照は可能
 }



constアサーション (as const)

as const は、オブジェクトや配列のリテラル型を保持するためのTypeScriptのアサーション構文である。

enumに相当するパターンを、通常のTypeScriptオブジェクトで実現するために広く使用される。

as constによる定数オブジェクトの定義

as const を使用することにより、オブジェクトの全プロパティが readonly かつリテラル型として扱われる。

 const Status = {
    Pending:   "pending",
    Active:    "active",
    Completed: "completed"
 } as const;
 
 // as constなし : { Pending: string; Active: string; Completed: string; }
 // as constあり : { readonly Pending: "pending"; readonly Active: "active"; readonly Completed: "completed"; }
 
 const current = Status.Active;   // 型: "active" (string ではなくリテラル型)


as constと型の抽出

typeofkeyof を組み合わせることにより、定数オブジェクトからキーの型と値の型を抽出できる。

 const Status = {
    Pending:   "pending",
    Active:    "active",
    Completed: "completed"
 } as const;
 
 // キーの型を抽出
 type StatusKeys = keyof typeof Status;
 // "Pending" | "Active" | "Completed"
 
 // 値の型を抽出
 type StatusValues = (typeof Status)[keyof typeof Status];
 // "pending" | "active" | "completed"


satisfies と組み合わせることにより、型チェックを維持しながらリテラル型を保持できる。

 type ColorDef = { hex: string; name: string; };
 
 const Colors = {
    red:   { hex: "#FF0000", name: "Red" },
    green: { hex: "#00FF00", name: "Green" },
    blue:  { hex: "#0000FF", name: "Blue" }
 } as const satisfies Record<string, ColorDef>;
 
 // satisfiesにより、Record<string, ColorDef>に適合しているかチェックされる
 // as constにより、リテラル型が保持される
 type RedHex = typeof Colors.red.hex;   // "#FF0000" (リテラル型)



enumを避けるべき場面

TypeScriptのenumは便利な機能だが、バンドルサイズやtree-shakingの点から、代替パターンが推奨される場面もある。

enumとユニオン型の比較

文字列enumとユニオン型を使用した場合の比較を以下に示す。

 // as const版 (推奨)
 const RequestState = {
    Idle:    "IDLE",
    Loading: "LOADING",
    Success: "SUCCESS",
    Error:   "ERROR"
 } as const;
 type RequestState = typeof RequestState[keyof typeof RequestState];
 
 // enum版
 enum RequestState {
    Idle    = "IDLE",
    Loading = "LOADING",
    Success = "SUCCESS",
    Error   = "ERROR"
 }
 
 // ユニオン型版
 type RequestState = "IDLE" | "LOADING" | "SUCCESS" | "ERROR";


下表に、enumとユニオン型の特徴を比較する。

enumとユニオン型の比較
観点 enum ユニオン型 as constパターン
記述の簡潔さ 中程度 高い 中程度
逆マッピング 数値enumのみあり なし なし
tree-shaking 非対応 (IIFEのため) 対応 対応
バンドルサイズ 大きい なし なし
型安全性 高い (5.0以降) 高い 高い
ランタイム参照 可能 不可 可能
追加の型定義 不要 不要 必要 (type定義)


Tree-shakingとバンドルサイズへの影響

enumのコンパイル結果であるIIFEパターンは、バンドラ (webpack、Rollup等) のtree-shakingの対象にならない。

enumを使用するだけでランタイムコードが生成されるため、使用しない定数もバンドルに含まれてしまう。

 // enumのコンパイル結果 (IIFEはtree-shakingされない)
 var Color;
 (function (Color) {
    Color["Red"]   = "RED";
    Color["Green"] = "GREEN";
    Color["Blue"]  = "BLUE";
 })(Color || (Color = {}));
 
 // as constのコンパイル結果 (通常のオブジェクトのため、tree-shakingが効く)
 const Color = {
    Red:   "RED",
    Green: "GREEN",
    Blue:  "BLUE"
 };


推奨パターン

用途に応じた推奨パターンを以下に示す。

用途別の推奨パターン
用途 推奨パターン
ランタイムでのenum参照が必要な場合 文字列enum または as const パターンを使用する。
パフォーマンスとバンドルサイズを最優先する場合 const enum を使用する。
ただし、型宣言ファイルとの互換性に注意する。
フロントエンド(Webアプリ)での使用 as const パターンを推奨する。
tree-shakingが効き、バンドルサイズを最小化できる。
ビットマスクや順序付き定数 数値enumを使用する。
逆マッピングが利用でき、ビット演算も自然に記述できる。


下表に、enum・const enum・as constの使い分けの指針を示す。

enum・const enum・as constの使い分け
用途 推奨パターン 理由
APIレスポンス値の管理 as constパターン tree-shakingが効き、バンドルサイズを削減できる。
内部フラグ・ビットマスク 数値enum 逆マッピングとビット演算が利用できる。
パフォーマンス重視の定数 const enum インライン展開によりランタイムコストがゼロ
外部公開ライブラリのAPI 文字列enum 型定義が明確で、利用者にとって分かりやすい。
コンパイル時のみ使用する定数 const enum ランタイムコードが生成されない。
型と値を同名で管理したい場合 as constパターン (型と値の同名定義) TypeScriptの型と値の名前空間を分離して活用できる。



関連情報