You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript中实现枚举通用选择项生成函数?

问题

我有多个TypeScript枚举,目前为每个枚举都写了重复的转换函数,示例如下:

getMyEnumSelectItems(): Observable<SelectItem[]> {
    const values = Object.values(MyEnum);
    return this.translate
      .stream(values.map((val) => `myEnum.${val}`))
      .pipe(
        map((translatedValues) =>
          values.map((val) => ({ label: translatedValues[`myEnum.${val}`] || val, value: val }))
        )
      );
  }

现在我想写一个通用的泛型函数来统一处理所有枚举,预期的伪代码如下:

getSelectItems<T extends Enum>(): Observable<SelectItem[]> {
    const values = Object.values(T);
    const camelCaseName = nameof(T).toCamelCase();

    return this.translate
      .stream(values.map((val) => `${camelCaseName}.${val}`))
      .pipe(
        map((translatedValues) =>
          values.map((val) => ({ label: translatedValues[`${camelCaseName}.${val}`] || val, value: val }))
        )
      );
  }

希望调用方式为:const selectItems = getSelectItems<MyEnum>();,请问有没有可行的实现方案?

可行方案

TypeScript的泛型类型信息在运行时会被擦除,无法直接通过泛型参数T获取枚举的名称和值。要实现通用函数,必须把枚举本身作为参数传入,再配合泛型约束保证类型安全。具体实现如下:

1. 定义泛型约束与辅助函数

先约束枚举类型的结构,再写一个大驼峰转小驼峰的辅助函数:

// 约束参数为枚举类型(键值对结构,值为字符串或数字)
type EnumType = Record<string, string | number>;

// 大驼峰转小驼峰的辅助函数
const toCamelCase = (str: string): string => {
  return str.charAt(0).toLowerCase() + str.slice(1);
};

2. 实现通用转换函数

基于原有逻辑抽象出通用函数,通过传入的枚举对象获取值和名称:

getSelectItems<T extends EnumType>(enumObj: T): Observable<SelectItem[]> {
    // 获取枚举的所有值,针对数字枚举可添加过滤逻辑
    const values = Object.values(enumObj) as Array<T[keyof T]>;
    // 获取枚举名称并转为小驼峰
    const enumName = enumObj.constructor.name;
    const camelCaseName = toCamelCase(enumName);

    return this.translate
      .stream(values.map((val) => `${camelCaseName}.${val}`))
      .pipe(
        map((translatedValues) =>
          values.map((val) => ({ 
            label: translatedValues[`${camelCaseName}.${val}`] || String(val), 
            value: val 
          }))
        )
      );
}

3. 调用方式

调用时直接传入枚举对象即可,TypeScript会自动推导泛型类型:

const selectItems = this.getSelectItems(MyEnum);

关键细节

  • 数字枚举处理:如果是数字枚举,Object.values会同时返回字符串类型的键和数字值,需要添加过滤逻辑:
    const values = Object.values(enumObj).filter(val => typeof val === 'number') as Array<T[keyof T]>;
    
  • 类型安全:泛型约束T extends EnumType保证传入的参数是枚举类型,返回的SelectItem数组的value类型会匹配枚举的值类型,避免类型错误。
  • 枚举名称可靠性:enumObj.constructor.name能稳定获取枚举的原始名称(比如MyEnum),前提是编译时没有开启代码混淆类名的选项。

内容的提问来源于stack exchange,提问作者MatterOfFact

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 07:25:35