Декоратор @IsEnum в библиотеке
class-validator используется для проверки того, что
значение свойства принадлежит заранее определённому перечислению (enum).
Он обеспечивает строгую валидацию входных данных на уровне типов и
значений, что особенно важно при работе с DTO в серверных
приложениях.
Основная задача — гарантировать, что переданное значение строго совпадает с одним из допустимых значений enum, независимо от того, используется строковый или числовой формат перечисления.
@IsEnum сравнивает значение свойства с набором значений,
извлечённых из объекта enum. В зависимости от типа enum (строковый или
числовой), поведение отличается:
IsEnum(entity: object, validationOptions?: ValidationOptions)
Параметры:
entity — объект enum, с которым производится
сравнение;validationOptions — дополнительные настройки поведения
валидации (сообщения, условия, группы).import { IsEnum } from 'class-validator';
enum UserRole {
Admin = 'admin',
User = 'user',
Guest = 'guest',
}
class CreateUserDto {
@IsEnum(UserRole)
role: UserRole;
}
В этом случае role может принимать только значения
'admin', 'user', 'guest'.
Строковые enum являются наиболее предсказуемым вариантом для
@IsEnum, так как не создают обратного маппинга.
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
class MoveDto {
@IsEnum(Direction)
direction: Direction;
}
Корректные значения строго ограничены строками, определёнными в enum.
Числовые enum в TypeScript создают двустороннюю структуру:
enum Status {
Active,
Inactive,
}
Фактически объект enum выглядит так:
{
0: "Active",
1: "Inactive",
Active: 0,
Inactive: 1
}
@IsEnum учитывает только корректные числовые значения,
игнорируя строковые ключи при проверке входных данных.
class AccountDto {
@IsEnum(Status)
status: Status;
}
Допустимыми значениями будут 0 и 1.
При работе с HTTP-запросами данные приходят как строки, поэтому возникает важный нюанс:
Пример проблемного случая:
{
"status": "1"
}
Даже если 1 допустим как число, строка "1"
не пройдет проверку без трансформации.
validationOptions позволяют задавать собственные
сообщения об ошибках.
import { IsEnum } from 'class-validator';
class PaymentDto {
@IsEnum(PaymentMethod, {
message: 'Недопустимый способ оплаты',
})
method: PaymentMethod;
}
Сообщение можно сделать динамическим:
message: (args) =>
`${args.property} должен быть одним из допустимых значений enum`
Для проверки массивов используется комбинация @IsEnum и
@IsArray с each: true.
import { IsEnum, IsArray } from 'class-validator';
enum Tag {
News = 'news',
Sport = 'sport',
Tech = 'tech',
}
class ArticleDto {
@IsArray()
@IsEnum(Tag, { each: true })
tags: Tag[];
}
Каждый элемент массива проверяется отдельно.
При использовании enum внутри вложенных объектов декоратор сохраняет локальную область действия:
class ProfileDto {
@IsEnum(UserRole)
role: UserRole;
}
class UserDto {
profile: ProfileDto;
}
Для корректной работы дополнительно применяются
@ValidateNested() и @Type() из
class-transformer.
undefined
и null@IsEnum не допускает null и
undefined по умолчанию.
Для разрешения таких значений требуется явное указание:
import { IsEnum, IsOptional } from 'class-validator';
class FilterDto {
@IsOptional()
@IsEnum(Status)
status?: Status;
}
Иногда enum используется как замена union типов:
type Role = 'admin' | 'user' | 'guest';
Однако @IsEnum работает только с объектами enum, поэтому
применяется альтернативный подход:
const Role = {
Admin: 'admin',
User: 'user',
Guest: 'guest',
} as const;
И затем:
@IsEnum(Role)
role: typeof Role[keyof typeof Role];
При использовании class-transformer важно учитывать
порядок обработки:
@IsEnumЕсли преобразование отключено, числовые значения могут приходить как строки и не проходить валидацию.
@IsEnum(Status)
status: Status;
Ошибка возникает, если приходит "Active" вместо
Status.Active или 0.
const Status = {
ACTIVE: 'active',
INACTIVE: 'inactive',
};
Без as const TypeScript не гарантирует корректную
типизацию, что может привести к неожиданным значениям.
Любые значения вне enum автоматически считаются ошибкой:
boolean значения.При использовании вместе с другими декораторами:
@IsString()
@IsEnum(UserRole)
role: UserRole;
@IsEnum становится финальной проверкой допустимых
значений после базовой проверки типа.
В крупных проектах рекомендуется:
@IsEnum только на границе входных
данных.При интеграции с Swagger через @nestjs/swagger, enum
автоматически документируется:
@ApiProperty({ enum: UserRole })
@IsEnum(UserRole)
role: UserRole;
Это позволяет синхронизировать документацию и валидацию без дублирования логики.