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

TypeScript通用枚举成员校验函数的类型收窄问题

TypeScript通用枚举校验函数的类型收窄解决方案

需求是实现一个通用函数,接收枚举类型与变量,校验变量是否为该枚举的成员,且校验通过后自动收窄变量类型。现有两种实现方案均存在问题:

现有方案的问题

  • 第一种方案定义:

    export function isEnumMember<T extends Record<string, K>, K>(value: unknown, enumType: T): value is K
    

    问题:校验通过后变量类型未被正确收窄,仍保持原类型(如unknown、string),因为TypeScript无法从T extends Record<string, K>的约束中准确推断出K为枚举的成员值类型。

  • 第二种方案将返回类型改为value is T:
    问题:在字符串枚举场景下,变量类型会变为string & typeof WORK_TYPE_ENUM这类交叉类型,无法直接适配prefix_${WORK_TYPE_ENUM}这类模板字符串的赋值需求,必须手动使用as断言才能正常工作。

正确的通用实现

export function isEnumMember<T extends Record<string, string | number>>(value: unknown, enumType: T): value is T[keyof T] {
  // 过滤数字枚举的反向映射键(只保留值为字符串或数字的枚举成员)
  const enumValues = Object.values(enumType).filter(v => typeof v === 'string' || typeof v === 'number') as T[keyof T][];
  return enumValues.includes(value as T[keyof T]);
}

方案说明

  1. 类型推断:T[keyof T]准确获取枚举的成员值类型(无论是字符串枚举还是数字枚举),校验通过后变量会被正确收窄为该类型。
  2. 兼容数字枚举:通过filter过滤掉数字枚举自动生成的反向映射键(数字键对应的字符串值),避免误判。
  3. 模板字符串适配:字符串枚举场景下,收窄后的类型为枚举成员的字符串字面量类型,可直接用于模板字符串拼接,无需额外断言。

使用示例

// 字符串枚举示例
enum WORK_TYPE_ENUM {
  FULL_TIME = "full-time",
  PART_TIME = "part-time"
}

function checkWorkType(val: unknown) {
  if (isEnumMember(val, WORK_TYPE_ENUM)) {
    // val类型被收窄为WORK_TYPE_ENUM,可直接用于模板字符串
    const labeledType = `work_type_${val}`;
    console.log(labeledType); // 类型为`"work_type_full-time" | "work_type_part-time"`
  }
}

// 数字枚举示例
enum STATUS {
  ACTIVE = 1,
  INACTIVE = 0
}

function checkStatus(val: unknown) {
  if (isEnumMember(val, STATUS)) {
    // val类型被收窄为STATUS
    const status: STATUS = val;
    console.log(status); // 类型为STATUS
  }
}

内容的提问来源于stack exchange,提问作者A-S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:27:42