TypescriptのEnumを嫌いになった話

TypescriptのEnumを嫌いになってしまいました

Enumは結構好きです。TypescriptのEnumの扱いがあまり好きではないです。
TypescriptのEnum使うより、Objectとして作成したほうがいいのでは?と思うことが多々あります。
一応、JavascriptにEnumがないので、TypescriptでEnumを作成しても、コンパイル後はObjectになるので、それが原因ということも含め、、、
最近記事を書いていないので、1年くらい前に思っていたことを、記事として残しておきます。w

理由1

enumの値が、Objectではなくただの文字列として扱われるため、Enumにする意味もないのかな?と思います。
PHPだとEnumの中にlabel()のようなメソッドを記載できるので便利なんですよね。。
また、ほかの記述法もあるので、Enumを使う理由があまりないように思います。

type Color = 'red' | 'blue' | 'green';
const ColorList = ['red', 'blue', 'green'] as const;
const ColorObject = { red: 'red', blue: 'blue', green: 'green' } as const;
enum ColorEnum {
  Red = 'red',
  Blue = 'blue',
  Green = 'green',
}

const red1: Color = 'red';
const red2: string = ColorList[0];
const red3: string = ColorObject.red;
const red4: string = ColorEnum.Red;

理由2

上記の件で、となればマジックナンバー問題が多い数字は、enumあり!!
と思っていたのもつかの間、別の問題がありました。 例えば、みんな利用するStatusでEnumを作成する場合、Object.keysで取得する際、文字列Enumと数値Enumで挙動が異なります。
データを一覧で撮りたい場合など、PHPだと、Status::cases()で取得できます。
なら、TypescriptでもObject.keys(StatusEnum)で取得できると思いきや、数値Enumの場合、余計な値が入ってしまいます。

enum StatusString {
  Inactive = 'inactive',
  Active = 'active',
}

enum StatusNumber {
  Inactive = 0,
  Active = 1,
}

console.log(Object.keys(StatusString)); // ['Inactive', 'Active']
console.log(Object.values(StatusString)); // ['inactive', 'active']
console.log(Object.entries(StatusString)); // [['Inactive', 'inactive'], ['Active', 'active']]

console.log(Object.keys(StatusNumber)); // ['0', '1', 'Inactive', 'Active']
console.log(Object.values(StatusNumber)); // ['inactive', 'active', 0, 1]
console.log(Object.entries(StatusNumber)); // [['0', 'inactive'], ['1', 'active'], ['Inactive', 0], ['Active', 1]]

理由3

はい。。。 そんでもって、僕なりの解決策を書いておきます。 ※ほかにもっといい方法ないかな。。。あればTsEnumを好きになりそう。

Helperの作成!!

これなら、PHPのようにlabelやその他fromなども作成できますね!! それでも面倒。。。

enum Status {
  Inactive = 0,
  Active = 1,
}

class StatusHelper {
  public static keys(): string[] {
    return Object.keys(Status).filter((key) => isNaN(Number(key)));
  }
  public static values(): any[] {
    return Object.values(Status).filter((value) => !isNaN(Number(value))).map((value) => Number(value));
  }
  public static entries(): [string, any][] {
    return Object.entries(Status).filter(([key, value]) => isNaN(Number(key))).map(([key, value]) => [key, Number(value)]);
  }
}

console.log(Object.keys(Status)); // ['0', '1', 'Inactive', 'Active']
console.log(Object.values(Status)); // ['inactive', 'active', 0, 1]
console.log(Object.entries(Status)); // [['0', 'inactive'], ['1', 'active'], ['Inactive', 0], ['Active', 1]]

console.log(StatusHelper.keys()); // ['Inactive', 'Active']
console.log(StatusHelper.values()); // [0, 1]
console.log(StatusHelper.entries()); // [['Inactive', 0], ['Active', 1]]

まとめ

上記の3つの理由から、TypescriptのEnumをあまり好きに利用しなくなりました。
リテラルを利用したり、普通にObjectとして、利用してます。

一応下に自分なりですが、最近の記述法を書いておきます。※enumを利用しない
まぁ、labelとか作成する場合は、Helperやりなんやり作成しないとですね。w

const Status = {
  Inactive: 0,
  Active: 1,
} as const;
type Status = typeof Status[keyof typeof Status];

console.log(Object.keys(Status)); // ['Inactive', 'Active']
console.log(Object.values(Status)); // [0, 1]
console.log(Object.entries(Status)); // [['Inactive', 0], ['Active', 1]]
Profile

s20024(やら)

プログラマー歴2年の初心者プログラマーです。
フロントエンドエンジニアです。たまにバックエンドもしています。
SNSは、あまりやっていないです。

ん。。。Laravelの記事しか書いて無くね?w
バックエンドエンジニアじゃん。w