【TypeScript】Enum型からUnion型に書き換える方法と具体例

JavaScript

TypeScriptではEnum型よりもUnoin型を利用したほうがよいという話をよく聞きます。1 2 3

今回はEnum型からUnion型に書き換えた具体例について紹介します。

Enum型を利用した例

以下はColorというEnum型を利用した例です。
showColorは引数のEnumの値に対応したログを出力するメソッドです。

enum Color {
  RED = "red",
  GREEN = "green",
  BLUE = "blue",
}

const showColor = (color: Color) => {
  if (color === Color.RED) {
    console.log("赤色です");
  }
  if (color === Color.GREEN) {
    console.log("緑色です");
  }
  if (color === Color.BLUE) {
    console.log("青色です");
  }
};

showColor(Color.RED);
// 赤色です

showColor(Color.GREEN);
// 緑色です

showColor(Color.BLUE);
// 青色です

// NG
// Enum型で定義されていないプロパティ
showColor(Color.YELLOW);
// => Property 'YELLOW' does not exist on type 'typeof Color'.(2339)

// NG
// Enum型ではない
showColor("red");
// => Argument of type '"red"' is not assignable to parameter of type 'Color'.(2345)

Enum型からUnion型に書き換えた例

Enum型のCorlorをUnion型のColorに書き換えた例が以下になります。
showColorの引数はEnum型からUnion型に変更されます。

// as constをつけることでプロパティをreadonlyにしている
const COLOR = {
  RED: "red",
  GREEN: "green",
  BLUE: "blue",
} as const;
// 以下のように評価される
// const COLOR: {
//     readonly RED: "red";
//     readonly GREEN: "green";
//     readonly BLUE: "blue";
// }

type Color = "red" | "green" | "blue";

const showColor = (color: Color) => {
  if (color === COLOR.RED) {
    console.log("赤色です");
  }
  if (color === COLOR.GREEN) {
    console.log("緑色です");
  }
  if (color === COLOR.BLUE) {
    console.log("青色です");
  }
};

showColor(COLOR.RED);
// 赤色です

showColor(COLOR.GREEN);
// 緑色です

showColor(COLOR.BLUE);
// 青色です

// OK
// 文字列リテラルを直接指定してもOK
showColor("red");
// 赤色です

// NG
// Union型に含まれてない
showColor("yellow");
// => Argument of type '"yellow"' is not assignable to parameter of type 'Color'.(2345)

keyof typeofを利用してUnion型を定義する

Union型の型定義はtype Color = "red" | "green" | "blue";でも問題ないのですが、keyoftypeofを利用することで文字列リテラルを直接記述する必要がなくなります。

文字列リテラルのタイプミスによるバグも防げるので、オブジェクトからUnion型を定義する場合はkeyoftypeofを活用するとよいでしょう。

keyoftypeofを利用してUnion型を定義した例は以下の通りです。

const COLOR = {
  RED: "red",
  GREEN: "green",
  BLUE: "blue",
} as const;
// 以下のように評価される
// const COLOR: {
//     readonly RED: "red";
//     readonly GREEN: "green";
//     readonly BLUE: "blue";
// }

type Color = typeof COLOR[keyof typeof COLOR];
// 以下のように評価される
// type Color = "red" | "green" | "blue"


const showColor = (color: Color) => {
  if (color === COLOR.RED) {
    console.log("赤色です");
  }
  if (color === COLOR.GREEN) {
    console.log("緑色です");
  }
  if (color === COLOR.BLUE) {
    console.log("青色です");
  }
};

showColor(COLOR.RED);
// 赤色です

showColor(COLOR.GREEN);
// 緑色です

showColor(COLOR.BLUE);
// 青色です

// OK
// 文字列リテラルを直接指定してもOK
showColor("red");
// 赤色です

// NG
// Union型に含まれてない
showColor("yellow");
// => Argument of type '"yellow"' is not assignable to parameter of type 'Color'.(2345)

type Color = typeof COLOR[keyof typeof COLOR];type Color = "red" | "green" | "blue"となる理由についてはTypeScriptの『typeof X[keyof typeof X]』の意味を順を追って理解するで詳細解説をしています。

さいごに

Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!

参考