class-validator
提供了声明式的数据完整性断言方法。它利用装饰器(decorators),帮助您快速定义数据验证的规则。
什么是class-validator
class-validator
是一个TypeScript库,它允许使用装饰器或非装饰器基础的验证。它依赖于validator.js
,这是一个字符串验证和清洗的库。它可以用在浏览器和Node.js环境下。
安装
使用npm安装class-validator
:
npm install class-validator --save
在 TypeScript 项目中,需要确保启用了装饰器:
// tsconfig.json
{
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
基础用法
使用class-validator
时,只需在类属性上添加验证装饰器:
import { IsInt, Min, Length, validate } from 'class-validator';
class Book {
@Length(10, 20)
title: string;
@IsInt()
@Min(0)
rating: number;
}
let book = new Book();
book.title = '短标题'; // 验证错误,标题太短
book.rating = -1; // 验证错误,评分低于最低限制
validate(book).then(errors => {
if (errors.length > 0) {
console.log('验证失败:', errors);
} else {
console.log('验证通过');
}
});
class-validator
提供了一系列的装饰器来实现各种验证规则。以下是一些常见的验证装饰器及其用法示例:
验证规则
- 基本验证
-
@IsDefined()
: 验证属性值是否已定义(不为null或undefined)。class Profile { @IsDefined() name: string; }
**
-
@IsEmpty()
: 验证属性值是否为空。class Profile { @IsEmpty() middleName: string; }
-
@IsNotEmpty()
: 验证属性值是否不为空。class Profile { @IsNotEmpty() lastName: string; }
- 类型验证
-
@IsBoolean()
: 验证属性值是否为布尔值。class Product { @IsBoolean() isActive: boolean; }
-
@IsString()
: 验证属性值是否为字符串。class Product { @IsString() name: string; }
-
@IsNumber()
: 验证属性值是否为数字。class Product { @IsNumber() price: number; }
-
@IsDate()
: 验证属性值是否为日期对象。class Appointment { @IsDate() date: Date; }
- 字符串验证
-
@IsEmail()
: 验证属性值是否为有效电子邮件地址。class User { @IsEmail() email: string; }
-
@IsFQDN()
: 验证属性值是否为完全合格的域名。class Website { @IsFQDN() domain: string; }
-
@IsPhoneNumber()
: 验证属性值是否为有效电话号码。class User { // 传入地区代码来验证不同国家的电话号码格式 @IsPhoneNumber('CN') phone: string; }
- 长度验证
-
@Length(min, max)
: 验证字符串长度。class User { @Length(10, 20) username: string; }
-
@MinLength()
: 验证字符串最小长度。class User { @MinLength(10) password: string; }
-
@MaxLength()
: 验证字符串最大长度。class User { @MaxLength(100) biography: string; }
- 数值验证
-
@Min()
: 验证数值最小值。class Rating { @Min(0) score: number; }
-
@Max()
: 验证数值最大值。class Rating { @Max(10) score: number; }
- 数组验证
-
@ArrayNotEmpty()
: 验证数组是否不为空。class User { @ArrayNotEmpty() friends: string[]; }
-
@ArrayMinSize(min)
: 验证数组最小长度。class User { @ArrayMinSize(1) siblings: string[]; }
-
@ArrayMaxSize(max)
: 验证数组最大长度。class User { @ArrayMaxSize(5) topMovies: string[]; }
- 复杂类型验证
-
@IsInstance()
: 验证是否为类的实例。class User { @IsInstance(Profile) profile: Profile; }
-
@ValidateNested()
: 验证嵌套对象。class User { @ValidateNested() profile: Profile; }
- 自定义验证
-
@CustomValidation()
: 应用自定义验证规则。import { ValidatorConstraint, ValidatorConstraintInterface, registerDecorator, ValidationArguments } from 'class-validator'; @ValidatorConstraint({ name: "customText", async: false }) export class CustomTextLength implements ValidatorConstraintInterface { validate(text: string, args: ValidationArguments) { // 自定义验证逻辑 } defaultMessage(args: ValidationArguments) { // 自定义违规信息 } }
class-validator
提供的验证器非常丰富,以上只是一小部分。在实际开发中,可以根据具体需求选择合适的验证器。更多的验证器及详细用法可以在class-validator
的GitHub页面查看。
高级用法
分组
您可以选择性地分组应用验证规则:
import { Min, validate } from 'class-validator';
class UserProfile {
@Min(13, { groups: ['registration'] })
age: number;
}
validate(userProfile, { groups: ['registration'] }).then(errors => {
// 处理验证结果
});
自定义验证器
通过扩展ValidatorConstraintInterface
定义自定义验证逻辑:
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments, registerDecorator } from 'class-validator';
@ValidatorConstraint({ async: true })
export class IsLongerThanConstraint implements ValidatorConstraintInterface {
validate(text: string, validationArguments: ValidationArguments) {
return text.length > validationArguments.constraints[0].length;
}
}
function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
return function (object: any, propertyName: string) {
registerDecorator({
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
constraints: [property],
validator: IsLongerThanConstraint,
});
};
}
class User {
@IsLongerThan("nickname")
fullName: string;
nickname: string;
}
// 用法略
白名单
自动从对象中去除没有注解的属性:
validate(obj, { whitelist: true }).then(errors => {
// 处理验证结果
});
忽略缺失属性
只验证对象中存在的属性:
validate(obj, { skipMissingProperties: true }).then(errors => {
// 处理验证结果
});
自定义消息
自定义消息允许您指定发生特定验证错误时的输出信息。在装饰器中指定message
属性可以定制错误消息。
例如:
import { IsInt, Min, validate } from 'class-validator';
class Product {
@IsInt({
message: '产品数量必须是一个整数'
})
quantity: number;
@Min(1, {
message: '产品数量必须大于等于1'
})
quantity: number;
}
let product = new Product();
product.quantity = 0.5;
validate(product).then(errors => {
if (errors.length > 0) {
console.log('验证失败:', errors.map(error => error.constraints));
}
});
错误处理
错误处理是验证过程的一部分。class-validator
返回一个ValidationError
数组,其中包含有关验证错误的详细信息。
例如:
import { Length, validate } from 'class-validator';
class User {
@Length(10, 20, {
message: '用户名的长度必须在$constraint1到$constraint2之间,但实际长度为$value'
})
username: string;
}
let user = new User();
user.username = 'ana';
validate(user).then(errors => {
if (errors.length > 0) {
console.error('验证失败:');
errors.forEach(error => {
console.error(`属性 ${error.property}: ${error.constraints?.length}`);
});
} else {
console.log('验证通过');
}
});
其他提示
其中一些有用的提示包括条件验证和数组验证。使用@ValidateIf()
装饰器可以实现条件性验证,而{ each: true }
选项用于数组中每个元素的验证。
条件验证示例:
import { ValidateIf, IsNotEmpty, validate } from 'class-validator';
class Post {
title: string;
@ValidateIf(o => o.title) // 只有当title属性存在时,才会验证text属性
@IsNotEmpty({
message: '当标题存在时,文本不能为空'
})
text: string;
}
let post = new Post();
post.text = '';
validate(post).then(errors => {
// 错误:当标题存在时,文本不能为空
});
数组验证示例:
import { ArrayMinSize, IsInt, validate } from 'class-validator';
class Movie {
@ArrayMinSize(1, {
message: '至少需要一名演员'
})
@IsInt({ each: true, message: '演员ID必须是整数' })
actorIds: number[];
}
let movie = new Movie();
movie.actorIds = [];
validate(movie).then(errors => {
// 错误:至少需要一名演员
});