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

如何用Class validator实现organisationId与organisation对象二选一校验

实现方案

可以通过class-validator的条件校验、嵌套校验能力,配合自定义互斥校验装饰器实现需求,具体步骤如下:

步骤1:自定义互斥字段校验装饰器

首先实现一个通用的互斥字段校验装饰器,用来保证两个字段必须传且仅传一个:

import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator';

export function IsMutuallyExclusive(relatedProperty: string, validationOptions?: ValidationOptions) {
  return function (target: Object, propertyName: string) {
    registerDecorator({
      name: 'isMutuallyExclusive',
      target: target.constructor,
      propertyName: propertyName,
      constraints: [relatedProperty],
      options: validationOptions,
      validator: {
        validate(value: unknown, args: ValidationArguments) {
          const relatedValue = (args.object as any)[relatedProperty];
          // 仅当两个字段恰好有一个存在时校验通过
          return (value !== undefined && relatedValue === undefined) 
              || (value === undefined && relatedValue !== undefined);
        },
        defaultMessage(args: ValidationArguments) {
          return `\`${args.property}\` 和 \`${args.constraints[0]}\` 必须传且仅传其中一个`;
        },
      },
    });
  };
}

步骤2:调整DTO类定义

修改创建用户的DTO,新增organisation字段,加上对应的校验装饰器,嵌套对象需要配合@Type做类型转换才能触发内部校验:

import { IsString, IsNumber, IsObject, ValidateNested } from 'class-validator';
import { Type } from 'class-transformer';
// 导入上面写的自定义装饰器
import { IsMutuallyExclusive } from './your-decorator-path';

export class Organisation {
  @IsString()
  public name: string;
}

export class CreateUserDto {
  @IsString()
  public name: string;

  @IsMutuallyExclusive('organisation')
  @IsNumber()
  public organisationId?: number;

  @IsMutuallyExclusive('organisationId')
  @IsObject()
  @ValidateNested()
  @Type(() => Organisation)
  public organisation?: Organisation;
}

校验效果说明

  • 两个字段同时传/同时不传:会触发互斥校验的错误提示
  • 仅传organisationId:会自动校验该字段是否为数字类型
  • 仅传organisation:会自动触发Organisation类内部的字段校验,比如name必须为字符串,不需要额外编写规则

注意事项

如果是在NestJS框架中使用,需要确保全局校验管道开启了transform: true配置,否则嵌套的organisation对象不会被转换为Organisation实例,内部校验规则不会生效,管道配置参考:

// main.ts中配置
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe({
    transform: true, // 开启自动类型转换
  }));
  await app.listen(3000);
}
bootstrap();

内容的提问来源于stack exchange,提问作者Vikas Kyatannawar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 21:24:03