本文总结了TypeScript枚举类型在日常开发中的常用实践,包括获取枚举键/值的联合类型、将枚举转换为对象、将枚举转换为数组等等......
获取枚举键的联合类型
可以使用keyof typeof获取由枚举属性名联合而成的联合类型
enum HttpMethod {
GET = 'get',
POST = 'post',
DEL = 'del'
}
type Method1 = keyof typeof HttpMethod
// 等同于
type Method2 = 'GET' | 'POST' | 'DEL'
获取枚举值的联合类型
可以使用模板字符串获取由枚举值联合而成的联合类型
enum HttpMethod{
GET = 'get',
POST = 'post',
DEL = 'del'
}
type Values1 = `${HttpMethod}`
// 等同于
type Values2 = 'get' | 'post' | 'del'
需要注意的是,数字枚举经过模板字符串转换后也会变成字符串类型
enum HttpMethod {
GET = 0,
POST = 1,
DEL = 2
}
type Values1 = `${HttpMethod}`
// 等同于
type Values2 = '0' | '1' | '2'
将枚举转换为对象
可以使用typeof将枚举转换为对象
enum HttpMethod {
GET = 0,
POST = 1,
DEL = 2
}
type HttpMethod2 = typeof HttpMethod
// 等同于
type HttpMethod3 = {
GET: 0,
POST: 1,
DEL: 2
}
将枚举值转换为数组
对于同构的枚举,可以使用Object.values将其转换为数字或者字符串数组
- 对于字符串枚举,直接使用
Object.values生成即可
enum HttpMethod {
GET = 'get',
POST = 'post',
DEL = 'del'
}
// ['get', 'post', 'del']
const httpMethods = Object.values(HttpMethod)
- 对于数字枚举,
Object.values生成的结果会包含枚举的键,因此需要用filter再做一次过滤
enum HttpMethod {
GET = 0,
POST = 1,
DEL = 2
}
// [0, 1, 2]
const httpMethods = Object.values(HttpMethod).filter((method) => typeof method === 'number')
这个方法可用于判断路由动态参数是否合法
例如:我们在路由声明中定义了名为locale的动态参数,可取值为zh或者en
import type { RouteObject } from 'react-router-dom';
const routes: RouteObject = [
{
paht: '/detail/:locale',
element: <App />
}
]
那么我们就可以在页面初始化时,判断当前的路由参数是否为合法值
如果不是,需要及时提示错误或者进行重定向,避免进一步报错导致页面白屏
import { useParams } from 'react-router-dom';
enum Locale {
ZH = 'zh',
EN = 'en'
}
const validLocales = Object.values(Locale)
export function App() {
const { locale } = useParams()
if (!validLocales.include(locale)) {
console.error('param locale is invalid')
return
}
return <div>App</div>
}
基于枚举和联合类型的组件入参设计
假设我们有一个供用户查看/编辑资源信息的表单组件,呈现只读、创建、编辑这3种不同的交互形态
enum Mode {
Readonly = 'readonly',
Create = 'create',
Edit = 'edit'
}
我们希望:
- 不同形态下,组件需要有不同结构的入参
- 父组件/业务方调用组件时,能够严格按照具体形态来进行传参
那么我们可以基于这个Mode枚举,设计3种形态下的组件入参类型
每种类型都包含一个属性mode取值为字面量,最后联合起来作为组件的入参
interface ReadonlyMode {
mode: Mode.Readonly
permission: string
}
interface CreateMode {
mode: Mode.Create
role: string
onCreate: () => void
}
interface EditMode {
mode: Mode.Edit
member: string
OnEdit: () => void
}
type FormProps = ReadonlyMode | CreateMode | EditMode