typescript :在运行时检查具有关联方法的枚举的枚举值

unftdfkk  于 2023-02-05  发布在  TypeScript
关注(0)|答案(1)|浏览(128)

为了增强代码的可靠性,我使用以下函数将原始字符串转换为枚举值:

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
}

然后,当我想把一个字符串转换成枚举类型时:

const enumValue = getSafelyEnumValue<MyEnum>(rawString, MyEnum)

这比执行简单的强制转换要好:

const enumValue = rawString as MyEnum

因为如果rawString不属于MyEnum,而getSafelyEnumValue属于MyEnum,那么最后这段代码不会抛出任何异常。当我有这样的简单枚举时,这个函数工作得非常好:

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;
        }
    }
}

当我使用这个模式时,我的方法getSafelyEnumValue不再编译,我在TS中遇到了这个错误:

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与枚举兼容有什么想法吗?

lf5gs5x2

lf5gs5x21#

枚举转换为POJO,举个例子:
typescript 中的此枚举...

enum OrderSideDto {
    SELL = "sell",
    BUY = "buy",
}

...在javascript中被转换为以下内容(请注意,基于数字的枚举有一个稍微不同的转换):

var OrderSideDto;
(function (OrderSideDto) {
    OrderSideDto["SELL"] = "sell";
    OrderSideDto["BUY"] = "buy";
})(OrderSideDto || (OrderSideDto = {}));

这个复杂的代码在执行时会产生以下结果(同样,基于数字的枚举也有点不同):

{
  "SELL": "sell",
  "BUY": "buy"
}

到目前为止一切顺利。现在,当你声明一个名称空间时,JS要么创建一个具有这个名称的对象,要么接受一个具有这个名称的现有对象。在你的例子中,后者发生了。无论哪种方式,声明的名称空间的内容都会被填充到请求的对象中。
这意味着,在您的例子中,对象填充了名称空间中声明的函数(不完全像我在这里描述的那样,但您明白了):

{
  "SELL": "sell",
  "BUY": "buy",
  "toOrderSide": (/* ... */) => { /* ... */ }
}

换句话说,您最终得到的对象具有枚举的属性和名称空间中的属性。

  • 然而 *,这些都不是你的问题。你的问题是你期望enumClass是一个任何类型的对象,其属性严格地只由字符串组成:
{ [s: string]: string }
  ^^^^^^^^^^^  ^^^^^^
       |       who's value is an string only
       |
  any property declarable with an string

因此,您还需要接受一个可调用对象(即Function)。

相关问题