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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 14:21:31