如何将DTO属性设为可选,但禁止全部属性为空?
实现class-validator类级验证:至少一个属性非空
你要的这种「所有属性可选,但不能全为空」的逻辑,class-validator没有现成的装饰器,但可以通过自定义类级验证器来实现,比用groups更贴合需求。
步骤1:自定义类级验证器
先写一个验证规则,用来检查DTO实例是否至少有一个属性非空:
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, registerDecorator, ValidationOptions } from 'class-validator'; @ValidatorConstraint({ name: 'atLeastOneNotEmpty', async: false }) export class AtLeastOneNotEmptyConstraint implements ValidatorConstraintInterface { validate(object: Record<string, any>, args: ValidationArguments) { // 遍历对象属性,判断是否存在非null/undefined的值 return Object.values(object).some(value => value !== null && value !== undefined); } defaultMessage(args: ValidationArguments) { return '更新操作至少需要提供一个属性(name/email/password)'; } } // 封装成类装饰器,方便直接用在DTO上 export function AtLeastOneNotEmpty(validationOptions?: ValidationOptions) { return function (object: any) { registerDecorator({ target: object.constructor, options: validationOptions, constraints: [], validator: AtLeastOneNotEmptyConstraint, }); }; }
步骤2:在DTO上使用自定义装饰器
把刚才的装饰器加到你的UpdateUsersDTO类上即可:
import { IsString, IsOptional, IsEmail, IsStrongPassword } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; import { AtLeastOneNotEmpty } from './path-to-your-validator'; // 替换成验证器实际路径 import { EmailIsUniq } from './your-custom-validators'; // 你的邮箱唯一验证器 @AtLeastOneNotEmpty() // 核心:添加类级验证规则 export class UpdateUsersDTO { @IsString() @IsOptional() @ApiProperty() name: string; @IsEmail() @EmailIsUniq({ message: 'This email is already being used' }) @IsOptional() @ApiProperty() email: string; @IsString() @IsStrongPassword({ minLength: 8, minLowercase: 1, minNumbers: 1, minSymbols: 1, minUppercase: 1, }) @IsOptional() @ApiProperty() password: string; }
补充说明
你之前尝试的groups验证器不适用这个场景——groups的作用是给验证规则分组,比如「新增用户」用一组规则、「更新用户」用另一组,但它无法实现「至少一个属性非空」这种类级别的逻辑判断。
内容的提问来源于stack exchange,提问作者Wilson de Freitas
相关产品推荐
相关产品推荐

