В библиотеке Yup контекст валидаторов строится вокруг функции
test, в которой доступен специальный объект исполнения.
Этот объект объединяет сведения о текущем значении, схеме, родительских
данных и пользовательском контексте, переданном при валидации.
Контекст в Yup не является глобальным состоянием. Он формируется
заново при каждом вызове .validate() или
.isValid() и привязывается к конкретному запуску проверки
схемы.
Ключевая особенность: this внутри пользовательских
валидаторов зависит от типа функции. Обычные функции получают
привязанный контекст, стрелочные функции — нет.
Метод .test() является основным инструментом для
создания пользовательских проверок:
Yup.string().test('custom-test', 'Ошибка валидации', function (value) {
return value === 'ok';
});
Внутри такой функции доступен контекст через this:
this.value — текущее значениеthis.originalValue — исходное значение до
преобразованийthis.path — путь поля в объектеthis.schema — текущая схемаthis.createError() — создание кастомной ошибкиthis.options — параметры валидацииПример использования:
Yup.number().test('positive-check', function (value) {
if (value <= 0) {
return this.createError({
message: `Поле ${this.path} должно быть положительным числом`
});
}
return true;
});
Контекст this работает только в обычных функциях. При
использовании стрелочных функций контекст теряется:
// НЕПРАВИЛЬНО
Yup.number().test('fail', (value) => {
console.log(this.path); // undefined
return value > 0;
});
// ПРАВИЛЬНО
Yup.number().test('ok', function (value) {
console.log(this.path); // работает корректно
return value > 0;
});
Причина заключается в том, что стрелочные функции не имеют
собственного this и наследуют его из внешнего окружения,
которое не связано с механизмом Yup.
При вызове валидации можно передавать внешний контекст:
schema.validate(data, {
context: {
role: 'admin'
}
});
Этот объект становится доступен внутри тестов:
Yup.string().test('role-check', function (value) {
if (this.options.context.role !== 'admin') {
return this.createError({ message: 'Недостаточно прав' });
}
return true;
});
Контекст передаётся только в момент выполнения и не хранится в самой схеме.
При валидации объектов особое значение имеет
this.parent, содержащий данные текущего уровня:
Yup.object({
password: Yup.string(),
confirm: Yup.string().test('match', function (value) {
return value === this.parent.password;
})
});
this.parent позволяет обращаться к соседним полям
объекта без необходимости дублирования значений.
Контекст Yup предоставляет доступ к метаданным схемы:
Текущий узел схемы, полезен для динамического анализа правил:
this.schema.type
Путь до поля в объекте:
'user.profile.email'
Используется при формировании сообщений об ошибках.
Тип значения схемы (string, number,
array, object).
Механизм ошибок в Yup централизован через createError,
который позволяет задавать не только сообщение, но и путь:
Yup.number().test('range', function (value) {
if (value > 100) {
return this.createError({
path: this.path,
message: 'Значение превышает допустимый диапазон'
});
}
return true;
});
Такой подход обеспечивает точное позиционирование ошибки в структуре данных.
Объект this.options содержит параметры текущей
валидации:
abortEarlycontextstripUnknownrecursiveПример:
Yup.string().test('debug', function (value) {
if (this.options.abortEarly) {
// поведение при раннем завершении
}
return true;
});
Контекст сохраняется и в асинхронных тестах:
Yup.string().test('async-check', async function (value) {
const role = this.options.context.role;
const allowed = await checkPermission(role);
if (!allowed) {
return this.createError({ message: 'Запрещено' });
}
return true;
});
Важно, что this остаётся доступным даже при
async/await.
Самая частая проблема — использование стрелочных функций в
.test().
Контекст существует только во время выполнения
.validate(). При обращении к schema напрямую
он отсутствует.
context не является глобальным состоянием схемы и не
сохраняется между вызовами.
Контекст и this.parent часто используются вместе:
Yup.object({
role: Yup.string(),
limit: Yup.number().test('limit-check', function (value) {
const role = this.parent.role;
const max = this.options.context.maxLimit;
return role === 'admin' || value <= max;
})
});
Такой подход позволяет объединять данные формы и внешние параметры системы.
Вложенные схемы сохраняют доступ к общему context, но
parent меняется на каждом уровне вложенности. Это позволяет
строить изолированные проверки при сохранении глобальных параметров
исполнения.