В библиотеке class-validator объект
ValidationError формируется при провале проверки одного из
полей класса-валидатора. Он содержит детализированную информацию о том,
какое именно значение нарушило правила валидации, какие ограничения были
заданы и какова структура вложенных ошибок.
Одним из ключевых элементов этой структуры является свойство
value, фиксирующее исходное значение поля
на момент выполнения валидации.
Типичный объект ValidationError включает несколько
взаимосвязанных полей:
Именно комбинация value, constraints и
children позволяет реконструировать контекст возникновения
ошибки без дополнительного логирования входных данных.
value отражает текущее значение свойства, которое было
проверено валидатором. Это значение фиксируется до
преобразований или после частичной трансформации, в зависимости от
конфигурации пайплайна.
В простейшем случае поведение выглядит следующим образом:
ValidationErrorvalue сохраняется значение, которое не прошло
проверкуПример логического представления:
{
property: "age",
value: -5,
constraints: {
min: "age must not be less than 0"
}
}
В данном случае value фиксирует число -5,
так как именно оно стало причиной нарушения ограничения
min.
В связке с class-transformer значение value
может отличаться от исходного входного payload. Это особенно заметно при
использовании transform: true.
При включённой трансформации:
В результате value отражает уже преобразованное
значение, а не исходный сырой input.
Пример:
// входные данные
{ age: "18" }
После трансформации:
{
property: "age",
value: 18,
constraints: {
min: "age must not be less than 0"
}
}
Здесь критически важно, что value уже приведено к
числу.
Существенная разница между value и target
заключается в уровне представления данных:
Пример структуры:
{
property: "email",
value: "invalid-email",
target: UserDto {
email: "invalid-email",
age: 25
}
}
value полезен при точечной диагностике, тогда как
target используется для анализа всего контекста состояния
объекта.
При работе с вложенными объектами и массивами value
сохраняет локальный фрагмент данных, относящийся к конкретному уровню
валидации.
Пример вложенной структуры:
class User {
@ValidateNested()
profile: Profile;
}
class Profile {
@IsString()
name: string;
}
При ошибке:
{
property: "profile",
value: {
name: 123
},
children: [
{
property: "name",
value: 123,
constraints: {
isString: "name must be a string"
}
}
]
}
Здесь верхнеуровневый value содержит весь объект
profile, а вложенные ошибки уточняют проблемное поле.
При валидации массивов value отражает:
Пример:
{
property: "tags",
value: ["js", 123, "node"],
children: [
{
property: "1",
value: 123,
constraints: {
isString: "each value in tags must be a string"
}
}
]
}
В данном случае:
value показывает состояние массива целикомПри использовании опций skipMissingProperties или
whitelist, значение value может быть:
undefined, если поле отсутствуетnull, если явно передано пустое значениеПример:
{
property: "username",
value: undefined,
constraints: {
isNotEmpty: "username should not be empty"
}
}
Такое состояние указывает на отсутствие данных до этапа проверки ограничений.
При создании кастомных декораторов value передаётся в
функцию проверки как текущий аргумент.
function customValidator(value) {
return typeof value === "string" && value.length > 3;
}
При ошибке:
{
property: "code",
value: "ab",
constraints: {
customValidator: "code is invalid"
}
}
Здесь value позволяет точно определить состояние данных
внутри пользовательской логики.
Несмотря на то что value отражает текущее состояние
данных, он не предназначен для модификации. Изменение этого поля не
влияет на исходный объект валидации и не пересчитывает ошибки.
Фактически:
value — диагностическое значениеtargetПопытки изменения value не приводят к обновлению
состояния валидации и не пересоздают структуру ошибок.
На практике значение value используется для:
Особое значение имеет сохранение оригинального типа данных, так как
именно через value определяется расхождение между ожидаемой
и фактической формой данных.
При сериализации объектов ошибок в JSON:
value сохраняется в исходной форме, если сериализация
не ограниченаvalue остаётся ключевым диагностическим полемПример сериализованного представления:
{
property: "price",
value: "free",
constraints: {
isNumber: "price must be a number"
}
}
Даже после сериализации значение остаётся тем же, что было на этапе проверки.
В сложных схемах DTO с множественными уровнями вложенности
value становится основным ориентиром для определения:
В сочетании с children оно позволяет реконструировать
полное дерево состояния данных в момент ошибки.
При использовании нескольких декораторов на одном свойстве:
@IsString()
@Length(5, 10)
username: string;
в случае ошибки value остаётся одинаковым для всех
нарушенных ограничений, так как оно фиксирует общее значение поля, а не
конкретный тип ошибки.
Пример:
{
property: "username",
value: "ab",
constraints: {
length: "username must be longer than 5 characters",
isString: "username must be a string"
}
}
Порядок применения валидаторов не изменяет содержимое
value. Однако влияет на набор constraints.
Независимо от того, какое правило сработало первым, value
остаётся неизменным источником входного состояния.
В реальных приложениях с многоступенчатой обработкой данных
value часто проходит через:
На каждом этапе оно сохраняет своё диагностическое значение, позволяя отслеживать расхождения между слоями обработки.