9

我的“AppState”枚举具有以下可能的枚举值:

export enum AppState {
  SUCCESS,
  ERROR,
  RUNNING
}

我有一个UpdateAppStateDTO,它应该接受除RUNNINGappState之外的每个枚举值。

export class UpdateAppStateDTO {
  @IsEnum(AppState)
  @NotEquals(AppState.RUNNING) // Doesn't work properly
  public appState: AppState;
}

对于路线,我有这个例子

  @Patch()
  public setState(@Body() { appState }: UpdateAppStateDTO): void {
    console.log(appState);
  }

如果请求有一个空的正文或一个无效的枚举值,比如“foobar”,appState我得到一个 400,这很好。

问题是当我发送“RUNNING”时,我仍然得到 200 而不是 400。

我怎样才能防止这种行为?

4

2 回答 2

14

我假设您正在发送 string 'RUNNING',并且您正在尝试确保那是未使用的内容,对吗?根据您目前所拥有的,您的枚举映射到这些值:

export enum AppState {
  SUCCESS = 0,
  ERROR = 1,
  RUNNING = 2
}

因此,如果您发送 string 'RUNNING',验证器会检查RUNNING !== 2实际上true导致成功验证的内容。装饰器检查在枚举的有效键中发送的@IsEnum()值,因此发送'RUNNING'通过该检查,因此为什么你没有在那里得到某种错误。

解决这个问题的最详细的方法是让你的枚举string enum像这样:

export enum AppState {
  SUCCESS = 'SUCCESS',
  ERROR = 'ERROR',
  RUNNING = 'RUNNING'
}

这将使每个AppState值映射到其对应的字符串,尽管这确实导致必须输入大量声明并可能导致重复代码。

管理此问题的另一种方法是将您的@NotEquals()枚举设置为枚举值提供的键,如下所示:

export class UpdateAppStateDTO {
  @IsEnum(AppState)
  @NotEquals(AppState[AppState.RUNNING])
  public appState: AppState;
}

但是请记住,当您appState稍后查看这种方法时,它仍然是一个数值而不是一个字符串。

您可以使用我为此制作的stackblitz来查看一些正在运行的代码。

于 2020-03-05T17:01:59.670 回答
2

问题是当我发送“RUNNING”时,我仍然得到 200 而不是 400。

似乎您正在使用字符串(!)“RUNNING”作为请求有效负载中的值,如下所示:

{ appState: "RUNNING" }

在这种情况下,IsEnum两者NotEquals都认为有效载荷是有效的。

这是为什么?

首先,数字枚举由打字稿反向映射,因此您的枚举在内部(作为 javascript 对象)表示如下:

{
  '0': 'SUCCESS',
  '1': 'ERROR',
  '2': 'RUNNING',
  'SUCCESS': 0,
  'ERROR': 1,
  'RUNNING': 2
}

现在类验证器的isEnum() 编码如下

isEnum(value: unknown, entity: any): boolean {
    const enumValues = Object.keys(entity)
        .map(k => entity[k]);
    return enumValues.indexOf(value) >= 0;
}

并且由于枚举是反向映射的,isEnum('RUNNNING', AppState)因此将返回 true。

同时NotEquals,它被编码为......

notEquals(value: unknown, comparison: unknown): boolean {
    return value !== comparison;
}

将字符串 'RUNNING' 与AppState.RUNNING(等同于2)进行比较,并得出结论认为这是有效的,因为'RUNNING' != 2.

所以你知道为什么有效载荷{ appState: "RUNNING" }会导致 200 而不是 400 状态代码。

我怎样才能防止这种行为?

枚举值AppState.RUNNING等同于,2因此当您发出请求时,您应该在有效负载中使用 的数值2

{ appState: 2 }

在上述情况下,类验证器的NotEquals验证器将正确拒绝请求,其响应包含:

"constraints": {
    "notEquals": "appState should not be equal to 2"
}
于 2020-03-05T17:19:05.027 回答