2020/07/29
TypeScriptの列挙型enumチートシート

列挙型(Enum)とは

列挙型は、事前にどんな種類があるのか分かっているようなものをすべて列挙して作る型のことです。数学や集合論の言葉を使って言えば、外延表記された有限集合をひとつの型とみなしてつくった型ともいえそうです。

じゃんけんゲームを実装しているとします。 じゃんけんではグー、チョキ、パーの3つの手が存在しますが、これをゲーム内でどのように表現しましょうか。

例えば定数で数値を上のように適当にあてるとしましょう。 すると、このゲームを実装するときにさまざまなデータ型が出現しますがその中で多くの問題に直面することになります。

例えば、2人のユーザが出した手番が相子か判定する関数の型は(a: number, b: number) => booleanとなります。静的型の機能に一種のドキュメントになる、というものがよく言われますが、これではコメントなしではどんな機能をもつ関数なのか判別できず、TypeScriptのもつ可読性を大きく損なうことになります。

また静的チェックによるバグ検出も正確でなくなります。 例えば、手番とその時の手を記録する関数を以下のように実装してしまうと、手番のnumberと実装のnumberが区別されずにコンパイルを通ってしまいます。

もしこれが下のようにJankenActionという3つの手をまとめた型をつかって書けたら可読性があがります。コンパイルエラーもでます。素敵です。

ソースコード

一部のコードはこちらで見られます

Enumの定義

最も簡単な定義

列挙型の定義は簡単で、要素を下のように羅列するだけです。

この結果この3つの要素は互いに区別されます。

静的チェックを整理するために列挙型を利用している際にはあまり意識する必要はないですが、このような要素の区別は実際には割り振る値を変えることによって実装されています。

値を指定する

上で示したように列挙型を定義した場合には互いに異なるように値が割り振られます(現行仕様は0から1ずつ値が増えた整数値を割り振る)。もしこの値を変更したい場合は定義時点で以下のように指定できます。

Enumを使って型をつくる

上のようにenumで種類を並べただけでもれっきとした型になります。なので列挙型を要素にもつ配列や列挙型を受け取る関数などを作ることもできますし、その型付けのしかたは他の型と変わりません。 このじゃんけんでの手の列挙型JankenActionを利用していくつか例を載せます。

配列

組(タプル)

連想配列(辞書)

列挙型を値に使う場合

値のところの型に利用したい列挙型を使うだけの簡単なもので宣言できます。

列挙型をキーに使う場合

こっちはちょっと複雑です。

JankenActionにある点すべてキーにする必要がある場合

この場合、以下の連想配列はこの型として扱われません

  • 一つでもJankenActionの要素が欠けているオブジェクト (e.g.) Chokiが欠けた{[JankenAction.Gu]: "グー", [JankenAction.Pa]: "パー"}はこの型ではコンパイルエラー
    Property 'Choki' is missing in type '{ Gu: string; Pa: string; }' but required in type 'Translator'
    
  • JankenActionの要素でないものがキーになっている時 (e.g.) 他のIdoがキーに入ったものはこの型ではコンパイルエラー
    Type '{ Gu: string; Pa: string; Choki: string; Ido: string; }' is not assignable to type 'Translator'.
    Object literal may only specify known properties, and '"Ido"' does not exist in type 'Translator'.
    

JankenActionの一部をキーにする場合

キーの型宣言をオプションにすることで、列挙型の任意の一部をキーにする連想配列を作成できます。

上と同じように、JankenActionにない要素をキーにすることはできません。

JankenActionの特定の要素をキーにする場合

これはキーにしたい特定の値をキーに指定すれば良いです。

関数

引数が列挙型の例

返り値が列挙型の例

Enumに静的メソッドを定義する

同じ名前をつけたnamespaceを使うことであたかも列挙型にメソッドを登録しているかのように扱うことができます。