Декоратор @Contains в библиотеке
class-validator используется для проверки наличия
подстроки внутри строкового значения свойства класса. Его основная
задача — гарантировать, что значение содержит определённый фрагмент
текста, без необходимости вручную писать кастомные валидаторы.
@Contains принимает строковый аргумент — подстроку,
которая должна присутствовать в проверяемом значении.
При валидации происходит простая операция проверки:
Contains(substring: string, validationOptions?: ValidationOptions)
substring — обязательная строка, которая должна
содержаться в значенииvalidationOptions — дополнительные параметры поведения
и сообщений об ошибкахimport { Contains } from "class-validator";
class UserDto {
@Contains("admin")
role: string;
}
В этом случае значение role должно содержать подстроку
"admin".
Допустимые значения:
"superadmin""admin-user""i-am-admin"Недопустимые значения:
"user""administrator" (важно: не содержит точную подстроку
"admin" как последовательность символов в нужном виде, если
проверка строгая к подстроке)"root"@Contains чувствителен к регистру. Это означает,
что:
@Contains("Admin")
role: string;
не пропустит значение:
"admin-panel"но пропустит:
"SuperAdmin"Таким образом, важно учитывать нормализацию строки до применения декоратора, если требуется регистронезависимая проверка.
@ContainsЧасто используется в системах доступа:
class AccessDto {
@Contains("role_")
scope: string;
}
Такой подход гарантирует, что все значения следуют единому соглашению именования:
role_adminrole_moderatorrole_userНекоторые системы используют строковые коды:
class TrackingDto {
@Contains("track-")
code: string;
}
Это позволяет ограничить ввод только значениями, соответствующими внутреннему формату:
track-001track-abc-99@ContainsНесмотря на простоту, декоратор имеет ряд ограничений:
Отсутствие семантической проверки Проверяется только наличие подстроки, без понимания контекста.
Риск ложных совпадений Например:
@Contains("admin")
"notadminrole"
формально проходит проверку, но может быть нежелательным значением.
Нет поддержки сложных правил Невозможно задать условия вроде:
@Contains часто используется совместно с другими
декораторами для повышения точности проверки.
@IsStringimport { IsString, Contains } from "class-validator";
class ExampleDto {
@IsString()
@Contains("prefix_")
value: string;
}
@MinLength и
@MaxLengthimport { Contains, MinLength, MaxLength } from "class-validator";
class CodeDto {
@MinLength(10)
@MaxLength(50)
@Contains("ID-")
code: string;
}
Такой набор ограничивает как структуру, так и размер строки.
null и undefined не проходят проверку без
дополнительных декораторов (@IsOptional)"" всегда не проходит проверку, если
подстрока не пустаПример:
@Contains("123")
value: any;
Значение 123 будет преобразовано в "123" и
успешно пройдет проверку.
@Contains("admin", {
message: "Значение должно содержать 'admin'"
})
role: string;
Возможности:
each,
groups@NotContains@NotContains выполняет противоположную задачу:
проверяет, что строка не содержит указанную
подстроку.
NotContains(substring: string, validationOptions?: ValidationOptions)
substring — запрещённая подстрокаvalidationOptions — параметры ошибкиimport { NotContains } from "class-validator";
class PasswordDto {
@NotContains("123")
password: string;
}
Значения:
"securePass!" — валидно"my123pass" — невалидно"123456" — невалидно@NotContainsclass InputDto {
@NotContains("<script>")
comment: string;
}
Используется как дополнительный слой защиты, но не заменяет полноценную санитизацию.
class FilenameDto {
@NotContains("..")
filename: string;
}
Позволяет исключить попытки обхода директорий:
file.txt — допустимо../secret.txt — недопустимо@NotContainsАналогично @Contains, проверка строго
регистрозависимая:
@NotContains("Admin")
не блокирует "adminPanel".
Любое значение, приводимое к строке, может пройти или не пройти проверку неожиданным образом:
123 → "123"null → "null"Это требует аккуратного использования вместе с
@IsString.
@Contains и @NotContainsОба декоратора могут использоваться одновременно, формируя более сложные правила:
class FilterDto {
@Contains("user")
@NotContains("test")
tag: string;
}
Такое сочетание задаёт условие:
"user""test"Примеры:
"user_active" — допустимо"test_user" — недопустимо"guest_user" — допустимоПопытка выразить бизнес-логику через @Contains приводит
к нечитаемым ограничениям:
@Contains("A")
@Contains("B")
@NotContains("C")
Такой код сложно сопровождать и масштабировать.
@Contains не заменяет @Matches. При
необходимости точного контроля структуры строки предпочтительнее
использовать регулярные выражения:
@Matches(/^admin_[a-z]+$/)
@NotContains не является механизмом защиты от атак.
Например:
Обе функции реализованы поверх простой строковой операции:
indexOf(substring) !== -1 для
@ContainsindexOf(substring) === -1 для
@NotContainsЭто объясняет их высокую производительность и одновременно ограниченную выразительность.
@Contains и @NotContains чаще всего
применяются в DTO-слое:
Их задача — не полная защита, а структурное ограничение входных данных до передачи в бизнес-логику.