enum型からunion型に置き換える方法

記事の概要

今回は、「未着手」「進行中」「完了」というデータをenum型で保持していると以下のように倍の数で定義していないデータが出力されてしまったので、調べてみた結果enum型からunion型に置き換えることにしたので備忘録として残したいと思います。

出力された内容

調べた内容

こちらを参考にすると、今回は「enumの利用を避けた方がいいとされる主な理由」の1に該当する事象だと考えられます。

問題が起きたコード(Before)

見た目などに必要な部分でも、今回の情報に必要ではないコードは消しています。

// Before
export enum MyTaskStatus {
    notStarted = 1,
    working = 2,
    completed = 3,
}

// 以下は共通部分
const toStringStatus = (num: number): string => {
    if (num === 3) {
        return '完了'
    } else if (num === 2) {
        return '進行中'
    } else {
        return '未着手'
    }
}

return (
	<div>
	    {Object.values(MyTaskStatus).map((status) => (
	        <FormControlLabel
	            label={toStringStatus(status)}
	        />
	    ))}
	</div>
)

置き換えた後のコード(After)

// After
export const MyTaskStatus = {
    notStarted: 1,
    working: 2,
    completed: 3,
} as const
type MyTaskStatus = typeof MyTaskStatus[keyof typeof MyTaskStatus]

解説

上記でも「enumの利用を避けた方がいいとされる主な理由」の1に該当すると記載しましたが、今回のパターンに合わせて書いていきたいと思います。

今回だとenum 型で以下のように3つ定義しましたが、結果としては「未着手」が4つと「進行中」と「完了」が1つずつ出力されています。

export enum MyTaskStatus {
    notStarted = 1,  // 未着手
    working = 2,     // 進行中
    completed = 3,   // 完了
}

これは、以下のコードが問題です。

コメントのあるelse文の箇所で3と2以外を全て「未着手」にしてしまっているので、もし想定していた1, 2, 3以外の数が入ってきた場合も受け入れてしまっています。

const toStringStatus = (num: number): string => {
    if (num === 3) {
        return '完了'
    } else if (num === 2) {
        return '進行中'
    } else {            // ここで3と2以外は全て'未着手'にしている
        return '未着手'
    }
}

そこで、以下のコードでunion型に置き換えて解決しました。

export const MyTaskStatus = {
    notStarted: 1,
    working: 2,
    completed: 3,
} as const
type MyTaskStatus = typeof MyTaskStatus[keyof typeof MyTaskStatus]

このコードのtype MyTaskStatus の中身としては、以下のようになっています。

type MyTaskStatus = 1 | 2 | 3

keyof, typeof の詳しい解説についてはこちらの記事がとてもわかりやすく説明してくださっているので参考にさせていただきました。

ちなみに上記の参考サイトと内容もリンクしているので、比べてみてみると更に理解が深まると思います。

コメント

タイトルとURLをコピーしました