【TypeScript】enumの使い方

更新日:2024/02/27

 

一般的なenum(列挙型)とは

enumは列挙という意味を持っています。

プログラミング用語では列挙型と呼ばれていて、ある変数がとりうる値を一つのまとまりとして列挙します。
そして変数などにセットできる値を列挙型で制限したり、および、プログラムの可読性を高めるために使用されます。

例えば、次のような曜日の番号を受け取って、曜日の名前を返す関数があるとします。

const dayName = (dayNumber:number):string=>{
    switch(dayNumber){
        case 0: return "日曜日";
        case 1: return "月曜日";
        case 2: return "火曜日";
         // 省略
    }
}
console.log( 2 );  // 結果: "火曜日"

この関数は、あらゆる数値を引数として受け取ります。
しかし、必要な値のみに制限できた方がいいです。

また、「0の時は日曜日」「3の時は水曜日」と数値と曜日の組み合わせで把握するのは少し分かりにくいです。
できれば、もっとわかりやすいコードに変更したいです。

そこで、列挙型を使用します。

 

enum型の定義

TypeScriptのenum型を使って、値の制限および値と名前の関連付けによる可読性の向上を行います。

enum型は次のコードのように、定義します。

enum DayWeek{
    SAN,
    MON,
    TUE,
    WEN,
    THU,
    FRI,
    SAT,
}

このenum型を使用して、dayName()関数を書き換えてみます。

const dayName = (dayNumber:DayWeek):string=>{
    switch(dayNumber){
        case DayWeek.SAN: return "日曜日";
        case DayWeek.MON: return "月曜日";
        case DayWeek.TUE: return "火曜日";
         // 省略
    }
}
console.log( dayName(DayWeek.TUE) );  // 結果: "火曜日"

数字よりも、DayWeek.TUEの方が何を意図しているのかわかりやすいですね。

 

enumの値

enumの各値は、いくつかの指定方法があります。

数値列挙型(省略型)

名前のみで値を省略した場合、0から連番で値が定義されます。

enum DayWeek{
    SAN,   // 0
    MON,   // 1
    TUE,   // 2
    WEN,   // 3
    THU,   // 4
    FRI,   // 5
    SAT,   // 6
}

値そのものに意味を持たせずに、フラグ的に使用したいとき便利です。

例えば、状態フラグとして使用するなどです。

enum Status { BUSY, ACTIVE,STOP};
const func = (stat:Status)=>{
  switch(stat){
    case Status.BUSY:
        /* 処理 */ return;
    case Status.ACTIVE:
        /* 処理 */ return;
    case Status.STOP:
        /* 処理 */ return;
  }
}

BUSYの値が 0 だろうが 100 だろうが関係なく動作するのがわかると思います。

数値列挙型

任意の数値を値として指定できます。

enum DayWeek{
    SAN = 0,
    MON = 1,
    TUE = 2,
    WEN = 3,
    THU = 4,
    FRI = 5,
    SAT = 6,
}

一部を省略することもできます。
省略部分は、連番がセットされます。

enum DayWeek{
    SAN,             // 0
    MON,            // 1
    TUE,             // 2
    WEN = 30,     // 30
    THU,             // 31
    FRI,              // 32
    SAT,             // 33
}

数値指定は、数値が何らかの意味を持っている時におこないます。

文字列列挙型

値に文字列をセットすることもできます。
ただし、それ以降は値を省略できません。

enum DayWeek{
    SAN,                            // 0
    MON,                           // 1
    TUE = "Tuesday",        //  "Tuesday"
    WEN = "Wednesday",   //  "Wednesday"
    THU = "Thursday",      // "Thursday"
    FRI = 5,                      //  5
    SAT = "Saturday",      //  "Saturday"
}

同名のenum型定義

enum型の定義は、複数に分けることができます。
ただし、値が重複しないように注意する必要があります。

enum DayWeek{SAN,MON,TUE}
enum DayWeek{THU=3,FRI,SAT}

 

enum型変数の値

enumで定義した型は、変数やプロパティに型アノテーションとして記述します。

enum DayWeek{
    SAN,  // 0
    MON,  // 1
    TUE,  // 2
    WEN,  // 3
    THU,  // 4
    FRI,  // 5
    SAT,  // 6
}
let a:DayWeek;

プロパティ形式での代入

値は、enum型のプロパティを代入します。

a = DayWeek.MON;
a = DayWeek.SAT;

存在しないキーを指定するとエラーです。

a = DayWeek.HELLO; // エラー:Property 'HELLO' does not exist on type 'typeof DayWeek'.

数値での代入

数値のみを値に持つenum型は、数値をセットすることもできます。
このとき、範囲外の数値をセットしてもエラーになりません

a = 1;     // 範囲内
a = 10;   // 範囲外:エラーにならない

ただし、全て数値ではない時はエラーです。
(※一つでも数値があれば、エラーになりません。)

enum DayWeek{
    SAN = "Sunday",
    MON = "Monday",
    TUE = "Tuesday",
    WEN = "Wednesday",
    THU = "Thursday",
    FRI = "Friday",
    SAT = "Saturday",
}
a = 1; // エラー:Type '1' is not assignable to type 'DayWeek'.

配列形式での代入

enum型を配列形式で値指定できます。

a = DayWeek["SAN"];

このとき、存在しないキーを指定できます。

a = DayWeek["HELLO"]; // エラーではない

これは、 DayWeek["HELLO"] が anyと評価されているからです。
そのため、noImplicitAnyオプションがtrueなら、エラーです。

noImplicitAnyオプションがtrue

a = DayWeek["HELLO"]; // エラー:Element implicitly has an 'any' type because index expression is not of type 'number'.

 

enumの実体

TypeScriptの型コンテキストはトランスパイル後に生成されるコードから削除されます。

しかしenum型は、生成コードに特有のコードを挿入します。

次のenum型をトランスパイルします。

enum DayWeek{SAN,MON,TUE,WEN,THU,FRI,SAT}

すると、次のようなコードを生成します。

var DayWeek;
(function (DayWeek) {
    DayWeek[DayWeek["SAN"] = 0] = "SAN";
    DayWeek[DayWeek["MON"] = 1] = "MON";
    DayWeek[DayWeek["TUE"] = 2] = "TUE";
    DayWeek[DayWeek["WEN"] = 3] = "WEN";
    DayWeek[DayWeek["THU"] = 4] = "THU";
    DayWeek[DayWeek["FRI"] = 5] = "FRI";
    DayWeek[DayWeek["SAT"] = 6] = "SAT";
})(DayWeek || (DayWeek = {}));

このコードは次のようなオブジェクトを生成します。

DayWeek{
    SAN:0, MON:1, TUE:2, WEN:3, THU:4, FRI:5, SAT:6,
    0:"SAN", 1:"MON", 2:"TUE", 3:"WEN", 4:"THU", 5:"FRI", 6:"SAT"
}

プロパティ名と同時に、数値インデックスが生成されているのがわかりますね。

前述のdayName()関数では、enum型のプロパティをswitch文で使用しています。
TypeScriptの型は動的なコードでは使用できません。
しかしenum型は実体があるので、型コンテキスト以外でも使用できるのです。

次の記事は、enum型実体の利用例です。

 

const enum

前項でenum型には実体があると書いていますが、次のようにconstを前方に記述すると実体が作成されません。

const enum DayWeek{SAN,MON,TUE,THU,FRI,SAT}

その代わりに、コード中のプロパティが実際の値に置き換わります。
次のコードは、トランスパイル後のコードです。

const dayName = (dayNumber) => {
    switch (dayNumber) {
        case 0 /* DayWeek.SAN */: return "日曜日";
        case 1 /* DayWeek.MON */: return "月曜日";
        case 2 /* DayWeek.TUE */: return "火曜日";
        // 省略
    }
};
console.log(dayName(2 /* DayWeek.TUE */));

const enum DayWeek{ }は、削除されて残っていません。

そして、DayWeek.SANが0に、他も該当する値に置き換わっています。

結果としてconstの方がコード量を減らすことができます。

前項の実体の使用例のようなケースなど、特に理由が無ければ、constにしておくといいでしょう。

■備考

preserveConstEnumsオプションをtrueにすると、実体が作成されます。

 

enumは非推奨?

ここまで解説してきたenumですが、非推奨らしいです。
なぜ非推奨なのでしょうか。
代わりの方法はあるのでしょうか。

次の記事解説しているので、読んでみてください。

更新日:2024/02/27

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。