Основная причина, по которой декораторы в Class-validator «не работают», почти всегда связана не с самой библиотекой, а с тем, как JavaScript/TypeScript окружение обрабатывает декораторы на этапе компиляции и выполнения. Class-validator полностью опирается на механизм декораторов и метаданных типов, поэтому любое отклонение в конфигурации приводит к тому, что валидация становится «пустой» или вовсе не активируется.
TypeScript по умолчанию не включает поддержку декораторов в том виде,
в котором их использует Class-validator. Если параметр
experimentalDecorators выключен, декораторы просто
игнорируются компилятором.
Ключевая настройка:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
При отсутствии этого флага код может выглядеть корректно, но фактически аннотации не будут применяться к классам и их свойствам. Это проявляется так:
@IsString() не валидирует строку@IsNotEmpty() не срабатываетВизуально это воспринимается как «декораторы не работают», хотя они просто не существуют в рантайме.
Class-validator использует reflect-metadata для
получения информации о типах свойств. Без этой информации многие
декораторы не могут корректно интерпретировать данные.
Необходимая настройка:
{
"compilerOptions": {
"emitDecoratorMetadata": true
}
}
Без неё происходит потеря типовой информации:
class User {
@IsString()
name: string;
}
В рантайме name становится просто undefined
с точки зрения метаданных, и валидатор не может определить ожидаемый
тип.
Даже при правильном tsconfig.json библиотека
reflect-metadata должна быть импортирована один раз до
использования любых декораторов.
Типичная ошибка — забытый импорт:
import "reflect-metadata";
Этот импорт должен выполняться до объявления любых классов с декораторами. Особенно важно это в следующих средах:
Если импорт отсутствует, метаданные просто не регистрируются, и Class-validator получает «пустую» модель.
Проблема часто проявляется в проектах с большим количеством модулей.
Если классы с декораторами импортируются до
reflect-metadata, результат становится непредсказуемым.
Плохой сценарий:
import { User } from "./user";
import "reflect-metadata";
Правильный порядок:
import "reflect-metadata";
import { User } from "./user";
Ошибка может быть скрытой, особенно если импорт происходит транзитивно через другие модули.
Современные сборщики могут изменять поведение декораторов:
Проблема заключается в том, что метаданные могут быть:
Например, SWC требует явного включения поддержки legacy decorators:
{
"jsc": {
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
}
}
}
Если этого не сделать, Class-validator не сможет восстановить структуру классов.
Во многих архитектурах Class-validator работает в связке с Class-transformer. Ошибка возникает, когда входные данные остаются обычными объектами без трансформации в классы.
Пример проблемного сценария:
const user = {
name: "John"
};
validate(user);
В этом случае декораторы не применяются, потому что user
— это не экземпляр класса.
Правильный подход:
import { plainToInstance } from "class-transformer";
const user = plainToInstance(User, {
name: "John"
});
Без трансформации Class-validator не видит метаданных класса.
Даже если класс определён корректно, частая ошибка — передача plain object вместо instance.
class User {
@IsString()
name: string;
}
const dto = { name: 123 };
validate(dto); // декораторы не работают
Class-validator ожидает экземпляр:
const instance = Object.assign(new User(), dto);
validate(instance);
В production-сборках некоторые инструменты могут удалять «неиспользуемые» классы. Это особенно характерно для:
Если класс не используется явно, он может исчезнуть из итогового бандла, а вместе с ним — и все декораторы.
Симптомы:
Смешивание модулей может приводить к тому, что
reflect-metadata подключается некорректно или поздно.
Типичная ситуация:
В таких случаях декораторы формально выполняются, но метаданные теряются.
Некоторые паттерны нарушают работу декораторов:
const User = class {
@IsString()
name;
};
или фабричные обёртки:
function createUser() {
class User {
@IsString()
name;
}
return User;
}
В подобных случаях метаданные могут не сохраняться стабильно, особенно при сложной сборке.
Class-validator опирается на поведение декораторов, которое менялось между версиями TypeScript. Несовместимость приводит к ситуации, когда:
Особенно критично при переходе между:
Метаданные генерируются только при наличии явного типа. Следующий код может не работать корректно:
class User {
@IsString()
name;
}
Правильный вариант:
class User {
@IsString()
name: string;
}
Без типа string система не может вывести metadata
design:type.
Если классы загружаются динамически (lazy import), возможна ситуация, когда валидация выполняется до инициализации метаданных.
const module = await import("./user");
validate(new module.User());
Если reflect-metadata не был загружен заранее, результат
будет непредсказуем.
Некоторые окружения (старые браузеры, урезанные рантаймы) не поддерживают Reflect API. Class-validator полностью зависит от:
Reflect.defineMetadataReflect.getMetadataПри отсутствии этих функций декораторы формально выполняются, но не сохраняют данные.
Сбой декораторов в Class-validator почти всегда является следствием разрыва между тремя слоями:
Нарушение любого из этих слоёв приводит к одинаковому внешнему эффекту — отсутствию валидации, хотя код выглядит корректным.