Nest.js中Class Validator实现邮箱/手机号二选一验证及自定义校验问题
在Nest.js中用class-validator实现邮箱/手机号二选一校验
一、class-validator是否支持「或」逻辑校验?
class-validator没有提供原生的@Or()这类直接实现或逻辑的装饰器,但可以通过自定义验证器结合内置校验工具函数来实现需求,这也是满足该场景最灵活的方案。
二、自定义IsEmailOrPhone验证器的正确实现方式
你遇到的核心问题是混淆了class-validator的装饰器和底层校验函数:@IsEmail()、@IsPhoneNumber()是用于给类字段添加校验规则的装饰器,而class-validator同时暴露了同名的纯函数(isEmail()、isPhoneNumber()),这些函数直接接收值并返回布尔校验结果,正好适配自定义验证器的validate方法要求。
1. 编写自定义验证器约束类
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator'; import { isEmail, isPhoneNumber } from 'class-validator'; @ValidatorConstraint({ name: 'isEmailOrPhone', async: false }) export class IsEmailOrPhoneConstraint implements ValidatorConstraintInterface { validate(value: string, args: ValidationArguments) { // 校验逻辑:满足邮箱格式,或满足指定区域(示例为中国)的手机号格式即可通过 return isEmail(value) || isPhoneNumber(value, 'CN'); } defaultMessage(args: ValidationArguments) { return '请输入有效的邮箱或手机号'; } }
2. 封装成可直接使用的装饰器
import { registerDecorator, ValidationOptions } from 'class-validator'; import { IsEmailOrPhoneConstraint } from './is-email-or-phone.constraint'; export function IsEmailOrPhone(validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { registerDecorator({ target: object.constructor, propertyName: propertyName, options: validationOptions, constraints: [], validator: IsEmailOrPhoneConstraint, }); }; }
3. 在请求DTO中使用
import { IsEmailOrPhone } from './is-email-or-phone.decorator'; export class AuthRequestDto { @IsEmailOrPhone({ message: '请提供有效的邮箱或手机号' }) isEmailOrPhone: string; // 其他请求字段... }
三、额外扩展说明
- 若需要支持多区域手机号校验,可修改
isPhoneNumber的第二个参数为区域数组(部分版本的class-validator支持数组格式,若不支持可自行扩展逻辑判断多个区域) - 如果需要异步校验(比如结合数据库查询做额外判断),只需将
ValidatorConstraint的async属性设为true,并让validate方法返回Promise<boolean>即可
内容的提问来源于stack exchange,提问作者Barun Bhattacharjee
相关产品推荐
相关产品推荐

