Декоратор @IsIn используется для проверки того, что значение поля принадлежит заранее заданному набору допустимых значений. Это один из базовых валидаторов библиотеки, позволяющий реализовать строгие ограничения на уровне схемы данных без написания пользовательских функций.
Основная идея заключается в сравнении входящего значения с массивом разрешённых вариантов. Если значение отсутствует в списке — валидация считается проваленной.
Поведение можно выразить следующим образом:
===)@IsIn(values: any[], validationOptions?: ValidationOptions)
values — массив допустимых значенийvalidationOptions — дополнительные параметры (сообщение
об ошибке, группы и т.д.)import { IsIn } from 'class-validator';
class UserDto {
@IsIn(['admin', 'user', 'moderator'])
role: string;
}
В этом случае поле role может принимать только одно из
трёх значений.
Если значение не входит в список:
const dto = new UserDto();
dto.role = 'superadmin';
Валидация вернёт ошибку:
role must be one of the following values: admin, user, moderator
Чаще всего @IsIn применяется для строковых перечислений:
class OrderDto {
@IsIn(['pending', 'paid', 'shipped', 'delivered'])
status: string;
}
Такой подход заменяет ручные проверки вида
status === '...'.
Допустимо использование числовых наборов:
class RatingDto {
@IsIn([1, 2, 3, 4, 5])
rating: number;
}
Важно учитывать, что сравнение строгое, поэтому строка
"1" не равна числу 1.
Хотя для boolean обычно используют @IsBoolean, возможен
и такой вариант:
class FeatureDto {
@IsIn([true, false])
enabled: boolean;
}
Поведение по умолчанию можно переопределить:
import { IsIn } from 'class-validator';
class ProductDto {
@IsIn(['book', 'electronics', 'clothing'], {
message: 'type должен быть одним из: book, electronics, clothing',
})
type: string;
}
При использовании вместе с class-transformer важно
учитывать преобразование типов:
import { Type } from 'class-transformer';
import { IsIn } from 'class-validator';
class TestDto {
@Type(() => Number)
@IsIn([10, 20, 30])
value: number;
}
Без @Type(() => Number) входное значение из JSON
может остаться строкой, и проверка не пройдет.
В контексте NestJS валидатор часто применяется в DTO-объектах:
import { IsIn } from 'class-validator';
export class CreateTaskDto {
@IsIn(['low', 'medium', 'high'])
priority: string;
}
В сочетании с ValidationPipe входные данные
автоматически проверяются до попадания в бизнес-логику.
Сам декоратор проверяет одно значение, а не массив входных данных.
Неправильное ожидание:
@IsIn(['a', 'b'])
tags: string[];
Здесь проверяется весь массив как единое значение, что почти всегда приведёт к ошибке.
Корректный подход:
import { IsIn, IsArray } from 'class-validator';
class TagsDto {
@IsArray()
@IsIn(['a', 'b', 'c'], { each: true })
tags: string[];
}
Ключевой момент — параметр each: true, который
заставляет валидатор применять проверку к каждому элементу массива.
Часто @IsIn используется как альтернатива enum:
enum Role {
Admin = 'admin',
User = 'user',
Moderator = 'moderator',
}
Вариант с enum:
@IsEnum(Role)
role: Role;
Вариант с IsIn:
@IsIn(['admin', 'user', 'moderator'])
role: string;
Различие:
@IsEnum — более строгий и типизированный подход@IsIn — более гибкий, особенно при динамических
спискахДопускается использование переменных:
const allowedStatuses = ['draft', 'published', 'archived'];
class PostDto {
@IsIn(allowedStatuses)
status: string;
}
Это полезно при централизованном управлении правилами.
Часто используется совместно:
import { IsString, IsNotEmpty, IsIn } from 'class-validator';
class AccountDto {
@IsString()
@IsNotEmpty()
@IsIn(['basic', 'pro', 'enterprise'])
plan: string;
}
Порядок декораторов не влияет на итоговую логику, но влияет на читаемость.
undefined и null@IsDefined)null — валидатор считает его невалидным,
так как оно не входит в списокПример:
class ExampleDto {
@IsIn(['a', 'b'])
value: string;
}
null → ошибка undefined → пропуск проверки
(если поле не обязательно)
Сравнение всегда строгое:
'1' ≠ 1true ≠ 'true'{} ≠ '[object Object]'Это особенно важно при работе с входящими JSON-данными.
Внутри происходит простая проверка через поиск значения в массиве допустимых вариантов. В большинстве реализаций это эквивалент:
values.includes(value)
Поэтому:
Set-логика (хотя
напрямую не используется в декораторе)1. Отсутствие each для массивов
@IsIn(['a', 'b'])
tags: string[];
2. Несовпадение типов
@IsIn([1, 2, 3])
value: string; // ошибка логики
3. Динамический список, изменяемый после объявления
Если массив мутируется после определения класса, поведение может стать непредсказуемым.
Использование @IsIn помогает:
При этом чрезмерное использование может привести к дублированию списков допустимых значений между слоями приложения, поэтому такие наборы часто выносятся в отдельные константы или конфигурационные модули.