Валидация типов данных в прикладных JavaScript-приложениях решает задачу контроля входных значений на уровне модели данных, исключая распространение некорректных значений в бизнес-логику. В экосистеме TypeScript и JavaScript эта задача часто переносится на уровень рантайма, поскольку статическая типизация не всегда гарантирует корректность данных, поступающих извне (HTTP-запросы, формы, очереди сообщений).
Библиотека Class-validator реализует декларативный подход к проверке типов и ограничений через использование декораторов и метаданных. Основная идея заключается в том, что правила валидации описываются прямо в классе модели, а затем применяются к экземплярам этих классов во время выполнения.
Ключевая особенность подхода — перенос описания требований к данным в
структуру класса. Вместо ручных проверок вида
typeof value === 'string' используются декораторы, которые
формируют набор правил.
Пример базовой модели:
import { IsString, IsNumber } fr om "class-validator";
class CreateUserDto {
@IsString()
name: string;
@IsNumber()
age: number;
}
Каждое поле становится носителем метаданных, описывающих допустимый тип данных. При этом сами декораторы не выполняют проверку немедленно — они лишь регистрируют правила, которые затем интерпретируются валидатором.
В основе работы лежит использование reflect-metadata,
позволяющего сохранять информацию о типах и декораторах в рантайме. При
объявлении класса библиотека фиксирует:
Во время выполнения создаётся описание правил, которое затем
используется функцией validate() для анализа объекта.
import { validate } from "class-validator";
const user = new CreateUserDto();
user.name = 123 as any;
user.age = "old" as any;
validate(user).then(errors => {
console.log(errors);
});
Результатом становится массив ошибок, каждая из которых содержит информацию о нарушении конкретного правила.
Строковые типы являются одним из наиболее часто проверяемых случаев, особенно при работе с HTTP-запросами.
Основные декораторы:
@IsString() — проверка, что значение является
строкой@IsNotEmpty() — проверка на непустое значение@Length(min, max) — ограничение длины строки@Matches(regex) — проверка по регулярному
выражениюПример комбинированной валидации:
import { IsString, IsNotEmpty, Length } from "class-validator";
class ProductDto {
@IsString()
@IsNotEmpty()
@Length(3, 50)
title: string;
}
Такой подход позволяет формировать строгие ограничения без ручных проверок в коде контроллеров или сервисов.
Работа с числами в JavaScript осложняется тем, что входящие данные
часто приходят в строковом формате. Поэтому проверка типа должна
учитывать не только number, но и корректность
преобразования.
Основные декораторы:
@IsNumber() — проверка числового типа@IsInt() — проверка целого числа@Min(value) — минимальное значение@Max(value) — максимальное значениеimport { IsInt, Min, Max } from "class-validator";
class PaginationDto {
@IsInt()
@Min(1)
@Max(100)
lim it: number;
}
Дополнительно может применяться опция преобразования входных данных (обычно на уровне пайпов или трансформации DTO), чтобы строковые значения приводились к числам до валидации.
Булевы значения в HTTP-контексте часто приходят в виде строк
"true" и "false", что требует аккуратной
обработки.
Доступные декораторы:
@IsBoolean() — проверка булевого типаimport { IsBoolean } from "class-validator";
class FeatureToggleDto {
@IsBoolean()
isEnabled: boolean;
}
При интеграции с внешними источниками данных часто требуется дополнительная трансформация значений до применения валидаторов.
Одна из сильных сторон библиотеки — поддержка вложенной валидации объектов и массивов.
Основные инструменты:
@IsArray() — проверка массива@ValidateNested() — рекурсивная валидация вложенных
объектов@Type() — указание типа элементов (часто используется с
class-transformer)import { IsArray, ValidateNested, IsString } from "class-validator";
import { Type } from "class-transformer";
class TagDto {
@IsString()
name: string;
}
class ArticleDto {
@IsArray()
@ValidateNested({ each: true })
@Type(() => TagDto)
tags: TagDto[];
}
Здесь важно, что без явного указания типа вложенные объекты не будут корректно валидироваться, так как JavaScript не сохраняет типовую информацию о массивах в рантайме.
Контроль обязательности полей играет ключевую роль при обработке входных DTO.
@IsDefined() — поле должно быть определено@IsOptional() — поле может отсутствовать@IsNotEmpty() — значение не должно быть пустымimport { IsDefined, IsOptional, IsString } from "class-validator";
class UpdateUserDto {
@IsOptional()
@IsString()
nickname?: string;
@IsDefined()
id: number;
}
Комбинация этих декораторов позволяет точно описывать поведение частичных обновлений и обязательных параметров.
Часто требуется проверка структурированных строковых значений:
Примеры декораторов:
@IsEmail()@IsUUID()@IsUrl()@IsDateString()import { IsEmail, IsUUID } from "class-validator";
class AccountDto {
@IsEmail()
email: string;
@IsUUID()
id: string;
}
Такие проверки снимают необходимость ручного парсинга и упрощают контроль входных данных на границе системы.
Валидационные правила можно комбинировать, создавая многоуровневые ограничения, которые проверяются последовательно. Ошибки при этом агрегируются и возвращаются в структурированном виде.
import { IsString, Length, Matches } from "class-validator";
class PasswordDto {
@IsString()
@Length(8, 32)
@Matches(/[A-Z]/)
value: string;
}
Такой подход позволяет формировать сложные бизнес-ограничения без нарушения читаемости модели.
Библиотека поддерживает разделение правил по группам, что позволяет использовать одну и ту же модель в разных сценариях.
import { IsString } from "class-validator";
class UserDto {
@IsString({ groups: ["create"] })
password: string;
@IsString({ groups: ["update"] })
nickname: string;
}
Группы позволяют применять различные наборы ограничений в зависимости от операции: создание, обновление, частичная модификация.
Некоторые типы проверок требуют обращения к внешним источникам: базе данных, API или кэшу. Для этого используются асинхронные валидаторы.
import { ValidatorConstraint, ValidatorConstraintInterface } from "class-validator";
@ValidatorConstraint({ async: true })
class IsUserAlreadyExist implements ValidatorConstraintInterface {
async validate(email: string) {
const user = await database.findUser(email);
return !user;
}
}
Асинхронные проверки позволяют интегрировать бизнес-логику в систему валидации без нарушения архитектурных границ слоёв приложения.
Результат валидации представляет собой структурированный массив объектов ошибок. Каждый объект содержит:
[
{
property: "name",
constraints: {
isString: "name must be a string"
}
}
]
Такая структура облегчает построение пользовательских сообщений и интеграцию с API-ответами.
При работе с внешними системами данные часто требуют предварительного преобразования. В связке с трансформерами можно автоматически приводить типы к ожидаемым значениям до проверки правил.
Это особенно важно при работе с JSON, где все значения приходят как строки или простые структуры без типизации.
Комбинация трансформации и валидации формирует устойчивый слой контроля входных данных, предотвращающий попадание некорректных значений в доменную модель.