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

如何在NestJS DTO中基于其他字段管控必填与可选字段?

解决方案

方案一:使用 @ValidateIf 装饰器实现条件必填

这种方式适合简单的条件关联校验,直接在字段上根据loginType的值动态启用必填规则。

修改后的LoginDto代码:

import { LOGIN_TYPE } from "src/utils/constants";
import { IsIn, IsNotEmpty, IsOptional, ValidateIf } from "class-validator";

export class LoginDto {
    // 当登录类型为手机号OTP时,手机号必填
    @ValidateIf((obj) => obj.loginType === LOGIN_TYPE.PHONE_NUMBER_OTP)
    @IsNotEmpty({ message: "手机号不能为空" })
    phoneNumber?: string;

    @IsOptional()
    fcmToken?: string;

    // 当登录类型为第三方平台时,accessToken必填
    @ValidateIf((obj) => [LOGIN_TYPE.GOOGLE, LOGIN_TYPE.APPLE, LOGIN_TYPE.FACEBOOK].includes(obj.loginType))
    @IsNotEmpty({ message: "第三方登录令牌不能为空" })
    accessToken?: string;

    @IsIn([LOGIN_TYPE.APPLE, LOGIN_TYPE.GOOGLE, LOGIN_TYPE.FACEBOOK, LOGIN_TYPE.PHONE_NUMBER_OTP])
    loginType: string = LOGIN_TYPE.PHONE_NUMBER_OTP;
}

说明:

  • @ValidateIf 接收回调函数,返回true时才会执行后续的校验规则
  • 移除了loginType的@IsOptional,因为登录类型是核心参数,即使前端不传也有默认值兜底
  • 字段后加?标记为可选类型,配合条件校验实现动态必填逻辑

方案二:自定义类级验证器(适配复杂场景)

如果需要更复杂的多字段关联校验逻辑,可以使用类级别的自定义验证器,对整个DTO实例进行校验。

步骤1:创建自定义验证器

// src/validators/login-validation.validator.ts
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from "class-validator";
import { LOGIN_TYPE } from "../utils/constants";

@ValidatorConstraint({ name: "loginValidation", async: false })
export class LoginValidation implements ValidatorConstraintInterface {
    validate(dto: any) {
        const { loginType, phoneNumber, accessToken } = dto;

        switch (loginType) {
            case LOGIN_TYPE.PHONE_NUMBER_OTP:
                return !!phoneNumber;
            case LOGIN_TYPE.GOOGLE:
            case LOGIN_TYPE.APPLE:
            case LOGIN_TYPE.FACEBOOK:
                return !!accessToken;
            default:
                return false;
        }
    }

    defaultMessage(args: ValidationArguments) {
        const { loginType } = args.object as any;
        return loginType === LOGIN_TYPE.PHONE_NUMBER_OTP 
            ? "手机号不能为空" 
            : "第三方登录令牌不能为空";
    }
}

步骤2:在DTO中应用验证器

import { LOGIN_TYPE } from "src/utils/constants";
import { IsIn, IsOptional, Validate } from "class-validator";
import { LoginValidation } from "./validators/login-validation.validator";

@Validate(LoginValidation)
export class LoginDto {
    @IsOptional()
    phoneNumber?: string;

    @IsOptional()
    fcmToken?: string;

    @IsOptional()
    accessToken?: string;

    @IsIn([LOGIN_TYPE.APPLE, LOGIN_TYPE.GOOGLE, LOGIN_TYPE.FACEBOOK, LOGIN_TYPE.PHONE_NUMBER_OTP])
    loginType: string = LOGIN_TYPE.PHONE_NUMBER_OTP;
}

说明:

  • 类级验证器会对整个DTO实例做校验,适合多字段联动的复杂规则
  • 可以在validate方法中编写任意自定义校验逻辑
  • defaultMessage可根据校验场景返回针对性错误提示

注意事项

  • 确保NestJS全局管道已启用ValidationPipe并配置transform: true(你已声明使用该配置)
  • 两种方案均无需在服务层处理校验逻辑,完全在DTO内部完成校验

内容的提问来源于stack exchange,提问作者Yogesh Rao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 01:03:32