TypeScript 列挙型(enum)の代替案
TypeScript の enum
は便利ですが、以下の理由で使わないことが推奨されることがあります:
- JavaScriptに変換されると余計なコードが出力される
- 値の双方向マッピングが不要な場合が多い
- ツリーシェイキングに不利
- 型安全・補完の観点で
as const
+ Union型の方が有利
✅ 代替案 1:as const
+ Union型
const Status = {
Draft: 'draft',
Published: 'published',
Archived: 'archived',
} as const;
type Status = typeof Status[keyof typeof Status];
// 使用例
function canEdit(status: Status) {
return status === Status.Draft;
}
✔ 特徴
- 実行時値と型を一致させられる
Object.values(Status)
で一覧取得可能- IDE補完が効く
- 型安全
✅ 代替案 2:Unionリテラル型
type Status = 'draft' | 'published' | 'archived';
function canEdit(status: Status) {
return status === 'draft';
}
✔ 特徴
- 最もシンプル
- IDE補完あり
- 軽量で読みやすい
❗ 注意
- 実行時に列挙値一覧を取得するには別途定数が必要
✅ 代替案 3:配列定数 + typeof T[number]
const Roles = ['admin', 'editor', 'viewer'] as const;
type Role = typeof Roles[number];
// 使用例
function hasWriteAccess(role: Role) {
return role !== 'viewer';
}
✔ 特徴
- 実行時の一覧と型定義を一括管理可能
- ループや
includes
チェックができる
if (Roles.includes('admin' as Role)) {
console.log('Valid role');
}
✅ 代替案 4:マッピングオブジェクト(Map風)
const Labels = {
admin: '管理者',
editor: '編集者',
viewer: '閲覧者',
} as const;
type Role = keyof typeof Labels;
✔ 特徴
- i18n(国際化)や表示名に便利
Record<Role, string>
型で自動補完も可能
❌ enum
の落とし穴(例)
enum Status {
Draft, // 0
Published, // 1
Archived // 2
}
const s = Status.Draft; // s === 0
❗ 問題点
- 値が数字になりやすくバグの原因に
Status[0] === 'Draft'
のように逆引きできるが、これは多くの場合不要- 実行時コードが増える(
enum
はJSでオブジェクトになる)
✅ まとめ:どれを使うべきか?
目的 | おすすめ代替法 |
---|---|
単純な状態管理 | Union型(例: 'open' | 'closed' ) |
実行時に一覧や表示が必要 | as const + typeof |
ユーザー定義型の管理 | 定数配列 + typeof T[number] |
UI表示(ラベル)付き状態管理 | マッピングオブジェクト(Record) |
🧾 補足:厳密な型安全のための tsconfig 設定
{
"compilerOptions": {
"strict": true,
"preserveConstEnums": false,
"isolatedModules": true
}
}