みかづきブログ・カスタム

基本的にはちょちょいのほいです。

TypeScriptのenumをループで列挙する 0️⃣

typescript-jp.gitbook.io

TypeScriptのenumはJavaScript変換時にオブジェクトに変換されます。
なので、forEachを使って要素を列挙したい場合は、Object.entriesを使えばOKです。

developer.mozilla.org

ただし、数値列挙型と文字列列挙型のenumで変換されるオブジェクトの要素数が異なってくるので注意が必要です。

数値列挙型の場合

enum Eto {
  '🐭' = 0,
  '🐮' = 1,
  '🐯' = 2,
  '🐰' = 3,
  '🐲' = 4,
  '🐍' = 5,
  '🐴' = 6,
  '🐏' = 7,
  '🐵' = 8,
  '🐔' = 9,
  '🐶' = 10,
  '🐗' = 11
};

このように値を数値に設定したenumは、

const Eto = {
  "0": "🐭",
  "1": "🐮",
  "2": "🐯",
  "3": "🐰",
  "4": "🐲",
  "5": "🐍",
  "6": "🐴",
  "7": "🐏",
  "8": "🐵",
  "9": "🐔",
  "10": "🐶",
  "11": "🐗",
  "🐭": 0,
  "🐮": 1,
  "🐯": 2,
  "🐰": 3,
  "🐲": 4,
  "🐍": 5,
  "🐴": 6,
  "🐏": 7,
  "🐵": 8,
  "🐔": 9,
  "🐶": 10,
  "🐗": 11
};

と、keyとvalueが入れ替わって二重に登録されたオブジェクトに変換されます。

なぜならば、

console.log(Eto[0]); // → 🐭

にも、

console.log(Eto[🐭]); // → 0

にも対応できるようにするためです。

enumとしては非常に便利なのですが、Object.entriesで配列で変換すると、

[
  ['0', '🐭'],
  ['1', '🐮'],
  ['2', '🐯'],
  ['3', '🐰'],
  ['4', '🐲'],
  ['5', '🐍'],
  ['6', '🐴'],
  ['7', '🐏'],
  ['8', '🐵'],
  ['9', '🐔'],
  ['10', '🐶'],
  ['11', '🐗'],
  ['🐭', 0],
  ['🐮', 1],
  ['🐯', 2],
  ['🐰', 3],
  ['🐲', 4],
  ['🐍', 5],
  ['🐴', 6],
  ['🐏', 7],
  ['🐵', 8],
  ['🐔', 9],
  ['🐶', 10],
  ['🐗', 11]
];

となってしまいます。
なので、

Object.entries(Eto).map(([ key, value ], i) => {
  console.log(`i: ${ i }, key:${ key }, value:${ value }`)});

という感じで、Object.entriesで列挙すると、

i: 0, key:0, value:🐭
i: 1, key:1, value:🐮
i: 2, key:2, value:🐯
i: 3, key:3, value:🐰
i: 4, key:4, value:🐲
i: 5, key:5, value:🐍
i: 6, key:6, value:🐴
i: 7, key:7, value:🐏
i: 8, key:8, value:🐵
i: 9, key:9, value:🐔
i: 10, key:10, value:🐶
i: 11, key:11, value:🐗
i: 12, key:🐭, value:0
i: 13, key:🐮, value:1
i: 14, key:🐯, value:2
i: 15, key:🐰, value:3
i: 16, key:🐲, value:4
i: 17, key:🐍, value:5
i: 18, key:🐴, value:6
i: 19, key:🐏, value:7
i: 20, key:🐵, value:8
i: 21, key:🐔, value:9
i: 22, key:🐶, value:10
i: 23, key:🐗, value:11

となります。
普通は半分列挙できれば充分なので、

Object.entries(Eto).map(([ key, value ], i) => {
if (i < Object.entries(Eto).length / 2) {
console.log(`i: ${ i }, key:${ key }, value:${ value }`);
}
});

と、if文を挟むことで半分の列挙にすることができます。

i: 0, key:0, value:🐭
i: 1, key:1, value:🐮
i: 2, key:2, value:🐯
i: 3, key:3, value:🐰
i: 4, key:4, value:🐲
i: 5, key:5, value:🐍
i: 6, key:6, value:🐴
i: 7, key:7, value:🐏
i: 8, key:8, value:🐵
i: 9, key:9, value:🐔
i: 10, key:10, value:🐶
i: 11, key:11, value:🐗

ちなみに、

enum Eto {
  '🐭',
  '🐮',
  '🐯',
  '🐰',
  '🐲',
  '🐍',
  '🐴',
  '🐏',
  '🐵',
  '🐔',
  '🐶',
  '🐗'
};

と、値を設定していないenumも数値列挙型となります。

文字列列挙型の場合

enum Eto {
  '🐭' = 'ne',
  '🐮' = 'ushi',
  '🐯' = 'tora',
  '🐰' = 'u',
  '🐲' = 'tatsu',
  '🐍' = 'mi',
  '🐴' = 'uma',
  '🐏' = 'hitsuji',
  '🐵' = 'saru',
  '🐔' = 'tori',
  '🐶' = 'inu',
  '🐗' = 'i'
};

このように値を文字列に設定したenumは、

{
  "🐭": "ne",
  "🐮": "ushi",
  "🐯": "tora",
  "🐰": "u",
  "🐲": "tatsu",
  "🐍": "mi",
  "🐴": "uma",
  "🐏": "hitsuji",
  "🐵": "saru",
  "🐔": "tori",
  "🐶": "inu",
  "🐗": "i"
}

と変換されます。
書いてから思いましたが、普通はkeyとvalueが逆ですね。

なので、

Object.entries(Eto).map(([ key, value ], i) => {
  console.log(`i: ${ i }, key:${ key }, value:${ value }`)});

と、Object.entriesを使って普通に列挙すれば、

i: 0, key:🐭, value:ne
i: 1, key:🐮, value:ushi
i: 2, key:🐯, value:tora
i: 3, key:🐰, value:u
i: 4, key:🐲, value:tatsu
i: 5, key:🐍, value:mi
i: 6, key:🐴, value:uma
i: 7, key:🐏, value:hitsuji
i: 8, key:🐵, value:saru
i: 9, key:🐔, value:tori
i: 10, key:🐶, value:inu
i: 11, key:🐗, value:i

とほぼほぼ期待通りに列挙できます。