TypeScript:如何让运行时枚举值校验兼容带方法的枚举?
问题
为提升代码可靠性,我用getSafelyEnumValue函数把原始字符串转成枚举值,这个函数会校验值的合法性,不合法就抛异常,比直接类型断言安全。但给枚举(比如OrderSideDto)通过同名命名空间加方法后,调用这个函数时出现了TypeScript类型不兼容错误,该怎么修改函数让它兼容带方法的枚举?
相关代码示例:
安全转换函数
export function getSafelyEnumValue<T>(value: string | undefined, enumClass: { [s: string]: string }): T { if (value === undefined) { throw new NullPointerException() } if (!Object.values(enumClass).includes(value)) { throw new UnknownEnumRawValueException(value) } return value as T }
带方法的枚举
export enum OrderSideDto { SELL = "sell", BUY = "buy", } export namespace OrderSideDto { export function toOrderSide(orderSideDto: OrderSideDto): OrderSideEntity { switch(orderSideDto) { case OrderSideDto.SELL: return OrderSideEntity.SHORT; case OrderSideDto.BUY: return OrderSideEntity.LONG; } } }
错误信息
Argument of type 'typeof OrderSideDto' is not assignable to parameter of type '{ [s: string]: string; }'. Property 'toOrderSide' is incompatible with index signature. Type '(orderSideDto: OrderSideDto) => Side' is not assignable to type 'string'
解决方案
问题根源是getSafelyEnumValue函数里enumClass的类型定义太严格,要求所有属性都是字符串,但带命名空间的枚举会额外包含函数类型的方法,导致类型不匹配。可以用以下两种方式修改:
方式一:放宽类型约束并过滤非枚举值
把enumClass的类型改成允许字符串或函数,然后在校验时过滤掉函数类型的值:
export function getSafelyEnumValue<T>(value: string | undefined, enumClass: { [s: string]: string | Function }): T { if (value === undefined) { throw new NullPointerException() } // 只保留字符串类型的枚举值用于校验 const enumValues = Object.values(enumClass).filter(v => typeof v === 'string') as string[]; if (!enumValues.includes(value)) { throw new UnknownEnumRawValueException(value) } return value as T }
方式二:用更精准的枚举类型约束
利用TypeScript的类型特性,定义枚举值的提取类型,同时过滤非枚举值:
// 提取枚举的原始值类型 type EnumValue<T> = T[keyof T]; export function getSafelyEnumValue<T extends Record<string, string | number>>(value: string | undefined, enumClass: T): EnumValue<T> { if (value === undefined) { throw new NullPointerException() } // 过滤掉方法等非枚举值,只保留字符串或数字类型的枚举原始值 const enumValues = Object.values(enumClass).filter(v => typeof v === 'string' || typeof v === 'number') as (string | number)[]; if (!enumValues.includes(value)) { throw new UnknownEnumRawValueException(value) } return value as EnumValue<T> }
修改后调用
直接调用即可,类型检查会正常通过:
const side = getSafelyEnumValue<OrderSideDto>("sell", OrderSideDto);
内容的提问来源于stack exchange,提问作者Jerem Lachkar
相关产品推荐
相关产品推荐

