NestJs中用class-validator实现二选一可选必填参数验证遇阻
解决NestJS中DTO可选属性二选一的验证问题
问题根源
你当前的实现把自定义验证装饰器加在a和b的属性上,但@IsOptional()会导致当属性不存在时,该属性的所有验证装饰器都不会执行。所以当payload只包含c时,a和b的自定义验证逻辑根本没触发,自然无法检测到错误。
正确实现方案:类级别验证装饰器
把验证逻辑从属性级别移到类级别,这样不管a和b是否存在,都会对整个请求对象做检查。
1. 实现类级自定义验证装饰器
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator'; export function OneOfOptionalRequired(requiredFields: string[], validationOptions?: ValidationOptions) { return function (target: Function) { registerDecorator({ name: 'oneOfOptionalRequired', target: target, options: { message: `必须提供${requiredFields.join('或')}中的至少一个`, ...validationOptions }, validator: { validate(_: unknown, args: ValidationArguments) { const payload = args.object as Record<string, unknown>; // 检查是否至少有一个指定属性存在且不为null/undefined return requiredFields.some(field => payload.hasOwnProperty(field) && payload[field] !== null && payload[field] !== undefined ); }, }, }); }; }
2. 修改DTO类
移除a、b属性上的@OneOfOptionalRequired,把装饰器加到类上,同时保留属性的@IsOptional和@IsString:
import { ApiProperty } from '@nestjs/swagger'; import { IsString, IsOptional } from 'class-validator'; import { OneOfOptionalRequired } from './your-decorator-path'; @OneOfOptionalRequired(['a', 'b']) class MyDto { @ApiProperty({ required: false }) @IsString() @IsOptional() a: string; @ApiProperty({ required: false }) @IsString() @IsOptional() b: string; @ApiProperty() @IsString() c: string; }
验证效果
{ a: 'some value', c: 'another value' }→ 验证通过{ b: 'some value', c: 'another value' }→ 验证通过{ a: 'some value1', b: 'some value2', c: 'another value' }→ 验证通过{ c: 'another value' }→ 验证失败,抛出错误:必须提供a或b中的至少一个
内容的提问来源于stack exchange,提问作者Rusty Gold
相关产品推荐
相关产品推荐

