TypeScript开发实践:枚举类型

160 阅读2分钟

本文总结了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