✍️

TypeScriptでのenumの書き方 3選

2022/03/01に公開

はじめに

TypeScriptでのenumの書き方ですが、大きく分けて2種類、派生系を含めて計3種類あると思っています。

本記事ではそれぞれを紹介したいと思います。

ユニオン型

ユニオン型は次のように定義し、

rank.ts
type Rank = 'Premium' | 'Standard' | 'Free'

export const displayLabel = (name: Rank): string => {
  return `rank: ${name}`
}

以下のように呼び出してみます。

index.ts
import { displayLabel } from './rank'

console.log(displayLabel('Premium')) // rank: Premium
console.log(displayLabel('hoge')) // error: Argument of type '"hoge"' is not assignable to parameter of type 'Rank'

型の指定があるので、IDE上ではerrorの表示が出ますし、トランスパイル時にターミナルでエラーの出力もあります。
結果として、型エイリアスで指定した文字列以外入力できないという制約を付与することができます。

この書き方のメリットは、ワンライナーで記載できる点です。
したがって、単純な制約を適用させたいときによく使用します。

配列を使ったユニオン型

上記の派生です。
displayLabel関数の引数をstringにして、stringがRankに含まれているかをチェックしたいという要件がある場合にただのユニオン型よりも簡単に記述することができます。

rank.ts
const ranks = ['Premium', 'Standard', 'Free'] as const
type Rank = typeof ranks[number]

const isRank = (name: string): name is Rank => {
  return ranks.some((value) => value.toUpperCase() === name.toUpperCase())
}

export const displayLabel = (name: string): string => {
  if (isRank(name)) {
    return `rank: ${name}`
  }
  return `${name}は不正なランクです`
}

以下のように呼び出してみます。

index.ts
import { displayLabel } from './rank'

console.log(displayLabel('Premium')) // rank: Premium
console.log(displayLabel('hoge')) // hogeは不正なランクです

配列で値を持っているので、enumの文字列を使ったループ処理を簡単に書くことができます。
ユニオン型よりも、少しややこしいことをしようとしたときの候補になってきます。

オブジェクトリテラル

TypeScript標準のenumの代替としてよく紹介されている方法です。

rank.ts
export const Rank = {
  Premium: 0,
  Standard: 1,
  Free: 2,
} as const

export type Rank = typeof Rank[keyof typeof Rank]

export const displayLabel = (name: Rank): string => {
  switch (name) {
    case 0:
      return 'rank: Premium'
    case 1:
      return 'rank: Standard'
    case 2:
      return 'rank: Free'
  }
}

次のようにして呼び出します。

index.ts
import { displayLabel } from './rank'

console.log(displayLabel(Rank.Premium)) // rank: Premium
console.log(displayLabel(Rank.Standard)) // rank: Standard

ユニオンのときと違い、0, 1, 2..のようなユニークなキーが明示されているのでDBに格納するときはnumberにしたいといった要件の場合に、特に有効な手段になってきます。

また、値はユニークであればいいので、正しい使い方かはわかりませんが、以下のように別名を保持させることも可能です。

rankJa.ts
export const Rank = {
  Premium: 'プレミアム',
  Standard: 'スタンダード',
  Free: 'フリー',
} as const

export type Rank = typeof Rank[keyof typeof Rank]

終わりに

今回3種類紹介しました。
先日、enumにプロパティ、メソッドを持たせられないか、検討したので、次回はそれについて書いてみようと思います。

「こういう書き方もあるのでは?」などありましたらコメントいただけると嬉しいです!

Discussion