You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 10:35:20