Метод when в Yup используется для построения условной
схемы валидации, когда правила проверки зависят от значений других полей
или текущего состояния данных. Это один из ключевых инструментов для
создания динамических форм, где логика валидации не является статичной и
меняется в зависимости от пользовательского ввода.
Валидация часто требует контекстности: поле может быть обязательным
только при выполнении определённого условия, либо его ограничения
меняются в зависимости от выбора пользователя. when
позволяет декларативно описывать такие зависимости внутри схемы Yup без
необходимости выносить логику валидации во внешний код.
Основная форма использования:
Yup.string().when('otherField', {
is: value => value === 'something',
then: schema => schema.required(),
otherwise: schema => schema.notRequired()
});
Наиболее читаемый и часто используемый формат:
when(key, options)
Где:
key — имя поля или массив полей, от которых зависит
текущее правило
options — объект с условиями:
is — значение или функция-предикатthen — схема, применяемая при выполнении условияotherwise — схема, применяемая в противном случаеПример:
const schema = Yup.object({
hasDiscount: Yup.boolean(),
discountCode: Yup.string().when('hasDiscount', {
is: true,
then: schema => schema.required('Введите промокод'),
otherwise: schema => schema.strip()
})
});
Один из самых распространённых сценариев — включение обязательности поля:
const schema = Yup.object({
deliveryType: Yup.string().required(),
address: Yup.string().when('deliveryType', {
is: 'courier',
then: schema => schema.required('Адрес обязателен при доставке курьером'),
otherwise: schema => schema.notRequired()
})
});
Здесь поле address становится обязательным только при
выборе доставки курьером.
is может быть не только значением, но и функцией, что
расширяет возможности проверки:
const schema = Yup.object({
age: Yup.number(),
guardianName: Yup.string().when('age', {
is: value => value < 18,
then: schema => schema.required('Для несовершеннолетних требуется опекун'),
otherwise: schema => schema.notRequired()
})
});
Функциональный подход удобен при сложных условиях сравнения.
when поддерживает массив зависимостей:
const schema = Yup.object({
country: Yup.string(),
city: Yup.string(),
postalCode: Yup.string().when(['country', 'city'], {
is: (country, city) => country === 'KZ' && city === 'Karaganda',
then: schema => schema.required(),
otherwise: schema => schema.notRequired()
})
});
Это позволяет учитывать контекст сразу нескольких значений.
Второй вариант when использует функцию-колбэк,
возвращающую схему:
Yup.string().when('field', (fieldValue, schema) => {
if (fieldValue === 'yes') {
return schema.required('Обязательное поле');
}
return schema;
});
Этот подход полезен, когда логика более гибкая и не укладывается в
структуру is/then/otherwise.
Пример с числовыми ограничениями:
const schema = Yup.object({
hasLimit: Yup.boolean(),
limit: Yup.number().when('hasLimit', {
is: true,
then: schema => schema.min(1).max(100).required(),
otherwise: schema => schema.notRequired()
})
});
Здесь диапазон значений применяется только при включённом флаге.
Условные проверки часто используются для изменения формата данных:
const schema = Yup.object({
type: Yup.string(),
value: Yup.string().when('type', {
is: 'email',
then: schema => schema.email('Некорректный email').required(),
otherwise: schema => schema.min(5)
})
});
Фактически одно поле может менять свою семантику в зависимости от контекста.
when корректно работает внутри вложенных структур:
const schema = Yup.object({
user: Yup.object({
role: Yup.string(),
permissions: Yup.string().when('role', {
is: 'admin',
then: schema => schema.required(),
otherwise: schema => schema.notRequired()
})
})
});
Важно учитывать, что путь role может относиться к тому
же объекту или быть внешним, в зависимости от структуры схемы.
В массивах when часто применяется для условий на
элементы:
const schema = Yup.object({
items: Yup.array().of(
Yup.object({
type: Yup.string(),
value: Yup.string().when('type', {
is: 'text',
then: schema => schema.required(),
otherwise: schema => schema.notRequired()
})
})
)
});
Каждый элемент массива может иметь собственную условную логику.
when и test часто используются вместе.
when задаёт условие применения схемы, а test —
кастомную проверку:
const schema = Yup.object({
password: Yup.string(),
confirmPassword: Yup.string()
.when('password', {
is: value => !!value,
then: schema => schema.required()
})
.test('match', 'Пароли не совпадают', function (value) {
return value === this.parent.password;
})
});
Такой подход позволяет разделять условие обязательности и логическую проверку.
При сложных сценариях лучше комбинировать несколько
when:
const schema = Yup.object({
plan: Yup.string(),
users: Yup.number(),
price: Yup.number()
.when('plan', {
is: 'pro',
then: schema => schema.min(100)
})
.when('users', {
is: value => value > 10,
then: schema => schema.min(200)
})
});
Каждое условие накладывает дополнительное ограничение.
when может использоваться для удаления поля из
результата:
const schema = Yup.object({
isVisible: Yup.boolean(),
secret: Yup.string().when('isVisible', {
is: false,
then: schema => schema.strip(),
otherwise: schema => schema
})
});
strip() полностью исключает поле из валидированного
объекта.
Неправильная ссылка на поле приводит к неработающей логике:
// ошибка: неправильное имя поля
Yup.string().when('wrongField', ...)
Также важно учитывать, что when зависит от текущего
состояния объекта, и при асинхронном изменении формы может требоваться
повторная валидация.
Некорректное использование функций в is без учёта типов
часто приводит к неожиданным результатам:
is: value => value == 1 // нежелательное нестрогое сравнение
when вычисляется во время валидацииwhen выполняются независимо на каждом уровне
схемыwhen становится центральным механизмом, когда форма
перестаёт быть фиксированной и превращается в набор правил, зависящих от
состояния данных.