もやぶろ

moyashidaisukeのブログだからもやぶろ。フリーランスのエンジニアのダイスケです。プログラム関連とかギター関連とか旅行関連とか色々。

【JavaScript】Symbolを駆使してenumぽいものを定義する

概要

JavaScriptでsymbol型を使う事によって、enumっぽいものの実装ができます。 そこそここなれてきたので紹介します。

前説

JavaScriptでenumを作るパターン

JavaScriptではenumが基本無いので、あの手この手でenumっぽいものを作る必要があります。

単純にconstで定義するパターン

こういうの

const ENUM = {
  HOGE: "hoge",
  FUGA: "fuga,
}

function isHoge(enum) {
  return enum === ENUM.HOGE);
}

www.sohamkamani.com

enumクラスを自作

qiita.com

他にもあると思います。

何が不満?

enumっぽいけど実体はただのObjectなので、enumを使わないでサボった実装でも動いてしまいます。

const ENUM = {
  HOGE: "hoge",
  FUGA: "fuga,
}

function isHoge(enum) {
  return enum === ENUM.HOGE);
  }

// 想定された使われ方
isHoge(ENUM.HOGE); // true

// さぼった使われ方
isHoge("hoge"); // true

Symbol(シンボル)とは

qiita.com

まあ今回のネタはほとんどこちらに書いてあるのですが、ポイントは

console.log(Symbol("Hoge") === Symbol("Hoge"));
// false

という事です。RubyのSymbolとはだいぶイメージが違うので気をつけましょう。

実装

const ENUM = {
  HOGE: Symbol("hoge"),
  FUGA: Symbol("fuga),
}

function isHoge(enum) {
  return enum === ENUM.HOGE);
}

// 想定された使われ方
isHoge(ENUM.HOGE); // true

// さぼった使われ方
isHoge("hoge"); // false
isHoge(Symbol("hoge")); // false

はい、これでENUMを使うことを強制できました。

jsonにしたり、シリアライズしてDBに保存したりしたい時は、

enumKeyString(enum) {
  switch (enum) {
    case ENUM.HOGE:
       return "hoge";
    case ENUM.FUGA:
       return "fuga";
  ]
}

とか

const ENUM_KEY_STRING = {
  [ENUM.HOGE]: "hoge",
  [ENUM.FUGA]: "fuga",
}

とかを用意してSymbolじゃない型でシリアライズしてあげるくらいしか手がありません。 ださいしめんどくさい、、、

Symbol("hoge")hogeはdescriptionなので、ロジックには使いたく無い。toStringしてもSymbol(hoge) になる、、、微妙、、

※typescriptを使えばいいじゃん、とか言わない事