Библиотека class-validator предназначена для декларативной валидации объектов в JavaScript и TypeScript с использованием декораторов. Основная идея заключается в том, чтобы описывать правила проверки прямо в классах моделей данных, а не разбрасывать проверки по бизнес-логике приложения.
Подход основан на метаданных и рефлексии: декораторы навешиваются на свойства классов, а затем библиотека анализирует эти метаданные и выполняет проверки.
В основе библиотеки лежат три ключевых концепции:
1. Декларативность Правила описываются рядом с данными, а не в отдельных функциях.
2. Декораторы Используются аннотации вида
@IsString(), @IsInt(),
@Length().
3. Валидация объектов классов Проверяются не «сырые» объекты, а экземпляры классов.
Для работы требуется включённая поддержка декораторов и рефлексии.
Установка:
npm install class-validator reflect-metadata
Дополнительно в TypeScript:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
Инициализация рефлексии в проекте:
import "reflect-metadata";
import { IsString, IsInt, Min, Max } from "class-validator";
class User {
@IsString()
name: string;
@IsInt()
@Min(18)
@Max(120)
age: number;
}
В этом примере:
name должен быть строкойage должен быть целым числом от 18 до 120import { validate } from "class-validator";
const user = new User();
user.name = "Alex";
user.age = 17;
validate(user).then(errors => {
console.log(errors);
});
Если есть ошибки, возвращается массив объектов
ValidationError.
Каждая ошибка содержит:
property — имя поляconstraints — список нарушенных правилchildren — вложенные ошибки (для объектов)Пример:
{
"property": "age",
"constraints": {
"min": "age must not be less than 18"
}
}
@IsString()
@IsNotEmpty()
@Length(3, 20)
@IsNumber()
@IsInt()
@Min(0)
@Max(1000)
@IsBoolean()
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(5)
Для сложных структур используется @ValidateNested():
import { ValidateNested } from "class-validator";
import { Type } from "class-transformer";
class Address {
@IsString()
city: string;
}
class User {
@ValidateNested()
@Type(() => Address)
address: Address;
}
Ключевой момент: без @Type() вложенные объекты не будут
корректно преобразованы.
Группы позволяют включать разные правила в зависимости от сценария:
class User {
@IsEmail({}, { groups: ["create"] })
email: string;
@IsOptional()
@IsString()
password?: string;
}
Запуск:
validate(user, { groups: ["create"] });
import { ValidatorConstraint, ValidatorConstraintInterface } from "class-validator";
@ValidatorConstraint({ name: "isEven", async: false })
class IsEvenConstraint implements ValidatorConstraintInterface {
validate(value: number) {
return value % 2 === 0;
}
defaultMessage() {
return "Number must be even";
}
}
Использование:
import { Validate } from "class-validator";
class Sample {
@Validate(IsEvenConstraint)
value: number;
}
Поддерживается работа с промисами, например при проверке уникальности в базе данных:
@ValidatorConstraint({ async: true })
class IsUniqueEmail {
async validate(email: string) {
const user = await database.findUser(email);
return !user;
}
}
Валидация часто используется вместе с преобразованием данных:
import { plainToInstance } from "class-transformer";
const obj = plainToInstance(User, rawData);
validate(obj);
Это позволяет автоматически превращать JSON в экземпляры классов.
@IsString()
@IsNotEmpty()
@Length(5, 50)
@IsOptional()
@IsString()
@IsInt()
@Min(1)
@Max(10)
class Item {
@IsString()
name: string;
}
class Order {
@ValidateNested({ each: true })
@Type(() => Item)
items: Item[];
}
each: true заставляет валидировать каждый элемент
массива отдельно.
validateSync(object);
Используется когда нет асинхронных правил. Возвращает ошибки сразу, без Promise.
Валидация часто размещается на уровне DTO (Data Transfer Objects), отделяя входные данные от бизнес-логики.
class CreateUserDto {
@IsString()
name: string;
@IsEmail()
email: string;
}
Такой подход снижает связность и упрощает поддержку кода.
По умолчанию библиотека возвращает полный список ошибок. Их можно:
Пример упрощения:
errors.map(e => ({
field: e.property,
message: Object.values(e.constraints || {})
}));
При большом количестве объектов важно учитывать:
validateSync быстрее, но менее
гибкоеemitDecoratorMetadatareflect-metadata@Type() для вложенных объектовawaitБиблиотека позволяет:
Использование декларативной валидации переносит ответственность за проверку данных ближе к их структуре. Это упрощает: