NestJS DTO 装饰器与 InterestionType/PickType 仍然强制执行 isDefined()



我正在通过IntersectionType进行DTO验证,并尝试使用PickType组合从另一个DTO添加可选字段。  例如,我创建了一个 AdminCodeDTO,它基本上是我在应用程序中使用 AdminCode 的所有规则,因此数字范围是一致的,以及任何其他定义。

export class AdminCodeDTO {
@IsDefined() @IsNumber() @Min(1) @Max(999) public AdminCode: number;
constructor(AdminCode?: number) {
this.AdminCode = AdminCode;
}
}

测试工作正常,验证确实运行。

it('should generate the DTO errors', async () => {
const DTOValidCheck: AdminCodeDTO = new AdminCodeDTO();
const Errors: Array<ValidationError> = await validate(DTOValidCheck);
expect(Errors.length).toBe(1);
expect(Errors[0].constraints['isDefined']).toBe('AdminCode should not be null or undefined');
expect(Errors[0].constraints['isNumber']).toBe('AdminCode must be a number conforming to  the specified constraints');
expect(Errors[0].constraints['max']).toBe('AdminCode must not be greater than 999');
expect(Errors[0].constraints['min']).toBe('AdminCode must not be less than 1');
});

我现在有另一个 DTO,它有其他数据,加上管理员代码,所以我使用 IntersectionType 来包含它。 

export class TimeEntryDTO extends IntersectionType (
AdminCodeDTO,
OtherDTO
) {}

在上述情况下,我的 AdminCodeDTO 现在是 OtherDTO 的一部分,并且所有验证都可以正常工作。 这按预期工作,我的管理员代码是必需的,包括所有验证规则。

现在我有一个案例,我希望存在 AdminCodeDTO 验证,但前提是填充了该字段。该字段不再是必填字段,而是可选的。 我相信PickType就是为了这个。因此,我认为我可以做到:

export class TimeEntryDTO extends IntersectionType (
PickType(AdminCodeDTO, ['AdminCode'] as const),
TimeDetailDTO,
) {}

我本来希望现在有我的TimeDetailDTO,然后是AdminCode字段,作为可选的。 情况似乎确实如此,因为包含该字段,但是,当我不提供 AdminCode 时,验证会导致问题,因为 @isDefined() 失败。

it('should not generate the AdminCode errors when AdminCode is not set', async () => {
TestDTO.AdminCode = undefined;
const Errors: Array<ValidationError> = await validate(TestDTO);
expect(Errors.length).toBe(0); // This should be the case, but it is returning all the validation
// The following errors are all returned, which I thought the PickType would have made the field optional, so the IsDefined() should not be processed.
expect(Errors[0].constraints['isDefined']).toBe('AdminCode should not be null or undefined');
expect(Errors[0].constraints['isNumber']).toBe('AdminCode must be a number conforming to the specified constraints');
expect(Errors[0].constraints['max']).toBe('AdminCode must not be greater than 999');
expect(Errors[0].constraints['min']).toBe('AdminCode must not be less than 1');
});

但是,我确实相信 InterestionType 正在结合所有这些,虽然 AdminCode 字段现在在类中可能是可选的,但验证装饰器在加载时仍然使用。

因此,在这种情况下有没有办法删除装饰器? 有没有办法添加一个,以便我可以将其从 AdminCodeDTO 中删除,然后在我希望强制执行 AdminCode 规则(例如定义 AdminCode)时添加它?

PickType只选择数组中指定的字段,如果该字段是否可选,它不会修改。您可以将PickType包装在PartialType中,以使该字段被选取可选。PartialType(PickType(AdminCodeDTO, ['AdminCode'] as const))

最新更新