前端常見(jiàn)的枚舉管理方式指南
寫在前面
前端里的“枚舉”,本質(zhì)上是在解決以下問(wèn)題:
- 限制狀態(tài)范圍
- 提高可讀性
- 提高類型安全
- 避免魔法字符串
- 方便 UI 映射
- 方便 AI 理解
下面作者為同學(xué)們總結(jié)了前端領(lǐng)域常見(jiàn)的枚舉方式:
Typescript 的 enum 枚舉類型
enum 是 Typescript 原生支持的枚舉類型。許多同學(xué)不知道的是,枚舉的定義方式是有區(qū)別的,定義方式會(huì)決定 enum 的應(yīng)用方式,分為 enum 和 const enum
enum
支持定義數(shù)字和字符串,定義/使用方式如下:
enum Status {
Pending,
Success,
Failed
}
Status.Pending // 0
enum Status {
Pending = 'pending',
Success = 'success',
Failed = 'failed'
}
Status.Pending // pending
數(shù)字類型支持反向映射,如:
Status[Status.Pending] // Pending
字符串類型不支持反向映射,因?yàn)?enum 編譯后會(huì)輸出大致這樣的代碼:
// input
enum Status {
Pending,
Success,
Failed
}
// output
const Status = {
Pending: 0,
Success: 1,
Failed: 2,
0: "Pending",
1: "Success",
2: "Failed"
}
字符串會(huì)在設(shè)計(jì)層面有很多限制,這里隨便舉個(gè)例子:
// input
enum Vector {
X = 'Y',
Y = 'Z',
Z = 'X'
}
// output 命名空間已經(jīng)明顯亂掉了, 假設(shè)訪問(wèn) Vector['X'],都不知道訪問(wèn)的是哪一個(gè)。
const Vector = {
X: 'Y',
Y: 'Z',
Z: 'X',
Y: 'X',
Z: 'Y',
X: 'Z'
}
const enum 枚舉
上文的 enum 是包含 運(yùn)行時(shí) 的,Typescript 會(huì)編譯出一個(gè) Javascript 對(duì)象,但對(duì) bundle 尺寸和性能有要求的庫(kù),需要一種更輕的枚舉類型,這就是后來(lái) Typescript 團(tuán)隊(duì)支持的 const enum 特性。定義/使用方式如下:
const enum Status {
Pending,
Success,
Failed
}
Status.Pending // 0
它不支持雙向映射,因?yàn)?ts 會(huì)在編譯時(shí)將 Status 抹去,只把 Status.Pending 的調(diào)用直接替換成字面量 0。
對(duì)象枚舉
絕大部分的前端工程師的工作還是以業(yè)務(wù)為主,更多只是單純的尋求 好用 + 實(shí)用 + 類型安全,基本不會(huì)在意 bundle 尺寸,實(shí)際上對(duì)于 Web App 來(lái)說(shuō),枚舉也不會(huì)帶來(lái)明顯的 bundle 尺寸增長(zhǎng)。 這也催生出了對(duì)象枚舉的定義方式,優(yōu)勢(shì)在于開發(fā)者可以自由的定義映射,類型使用也更加明確簡(jiǎn)單。
const Status = {
Pending: 'pending',
Success: 'success',
Failed: 'failed'
} as const
// as const 是必須的,影響下面的 type Status,對(duì) as const 感興趣的同學(xué)可以去問(wèn)一下 AI,這里就不展開了。
const StatusLabels = {
[Status.Pending]: '準(zhǔn)備中',
[Status.Success]: '成功',
[Status.Failed]: '失敗',
}
// 這個(gè)類型工具可以提取成通用工具
type ValueOf<T> = T[keyof T]
type Status = ValueOf<typeof Status> // 'pending' | 'success' | 'failed'
Status.Pending // 'pending'
StatusLabels[Status.Pending] // '準(zhǔn)備中'
enum-plus
對(duì)象枚舉雖然一定程度的解決了業(yè)務(wù)問(wèn)題,但定義起來(lái)實(shí)在有點(diǎn)復(fù)雜,雖然這對(duì)于 AI 來(lái)說(shuō)不是什么難事,但枚舉的信息密度非常低,不夠內(nèi)聚,關(guān)注點(diǎn)不夠聚焦,AI 也經(jīng)常犯迷糊。 但好在開發(fā)社區(qū)也有解決方案,比如 enum-plus。
import { Enum } from 'enum-plus'
const WeekEnum = Enum({
Sunday: { value: 0, label: 'I love Sunday' },
Monday: { value: 1, label: 'I hate Monday' },
});
WeekEnum.Sunday; // 0
WeekEnum.items[0].key; // 'Sunday'
WeekEnum.items[0].label; // 'I love Sunday'
作者找到這個(gè)庫(kù)的時(shí)候也是想要直接集成到項(xiàng)目里的,因?yàn)樗δ芊浅XS富,提供了 非常非常多 的 api。但同時(shí)我也覺(jué)得 api 過(guò)于復(fù)雜了,并且似乎類型約束相對(duì)松散,無(wú)法直接完成遷移(除非犧牲類型安全)比如:
import { Enum } from 'enum-plus'
const WeekEnum = Enum({
Sunday: { value: 0, label: 'I love Sunday' },
Monday: { value: 1, label: 'I hate Monday' },
})
console.log(WeekEnum.Sunday)
// 這里不會(huì)報(bào)類型錯(cuò)誤,但 `2` 不是一個(gè)合法的枚舉值,enum-plus 在這種情況下會(huì)返回 undefined,雖然也是合理的,但作者更傾向于嚴(yán)格一些類型約定。
console.log(WeekEnum.label(2))
enumOf
最后是作者自己的版本,個(gè)人比較滿意。實(shí)現(xiàn)較為輕量,api 也比較簡(jiǎn)單,并且類型安全,國(guó)際化支持也非常容易,同時(shí)開源并集成到了 rattail 工具庫(kù)里,有需要的同學(xué)可以自取。下面是常用案例。
import { enumOf } from 'rattail'
const Status = enumOf({
Success: { value: 0, label: 'Success' },
// 字段支持函數(shù)返回,國(guó)際化支持很簡(jiǎn)單。
Warning: { value: 1, label: () => t('global.warning') },
})
Status.Success // 0
Status.label(Status.Success) // 'Success'
Status.options()
/*
[
{ value: 0, label: 'Success'},
{ value: 1, label: 'Warning' },
]
*/
Status.values() // [0, 1]
Status.labels() // ['Success', 'Warning']
你也可以借助 rattail 內(nèi)置的函數(shù)去調(diào)整 .options() 返回的數(shù)據(jù)結(jié)構(gòu),這個(gè)在業(yè)務(wù)開發(fā)里很常見(jiàn)。
import { rekey } from 'rattail'
Status.options().map(option => rekey(option, { value: 'key' }))
/*
[
{ key: 0, label: 'Success'},
{ key: 1, label: 'Warning' },
]
*/
你也可以選擇擴(kuò)展更多字段,它們都會(huì)有完善的類型推導(dǎo)。
const Status = enumOf({
Success: { value: 1, label: 'Success', color: 'green' },
Warning: { value: 2, label: 'Warning', color: 'orange' },
})
Status.option(Status.Success).color // 'green'
寫在最后
到此這篇關(guān)于前端常見(jiàn)的枚舉管理方式指南的文章就介紹到這了,更多相關(guān)前端枚舉管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
layer子層給父層頁(yè)面元素賦值,以達(dá)到向父層頁(yè)面?zhèn)髦档男Ч麑?shí)例
下面小編就為大家?guī)?lái)一篇layer子層給父層頁(yè)面元素賦值,以達(dá)到向父層頁(yè)面?zhèn)髦档男Ч麑?shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09
用JavaScript 判斷用戶使用的是 IE6 還是 IE7
判斷IE瀏覽器的腳本,方便根據(jù)瀏覽器不懂,支持不同的代碼的分別調(diào)用。2008-01-01
bootstrapValidator 重新啟用提交按鈕的方法
bootstrapValidator 使用中,由于字段檢查等原因,致使提交按鈕失效。如何重新啟用提交按鈕呢?下面小編給大家介紹下bootstrapValidator 重新啟用提交按鈕的方法,需要的朋友可以參考下2017-02-02

