Множественные условия

Условная валидация как основа сложных схем

Библиотека Yup предоставляет декларативный механизм описания схем валидации, где каждое поле может зависеть от состояния других полей объекта. Это позволяет строить не статические правила, а динамические, изменяющиеся в зависимости от контекста данных. Ключевым инструментом для реализации таких сценариев выступает метод when, а также расширенный механизм test, который позволяет задавать произвольную логику проверки.

Условная валидация становится критически важной в формах, где структура данных не фиксирована: регистрационные формы с разными типами пользователей, конфигурационные интерфейсы, многошаговые формы и сложные бизнес-правила.


Метод when и базовая комбинация условий

Метод when используется для привязки валидации поля к значению другого поля. Базовая форма предполагает один зависимый параметр:

import * as Yup from 'yup';

const schema = Yup.object({
  isCompany: Yup.boolean(),
  companyName: Yup.string().when('isCompany', {
    is: true,
    then: schema => schema.required('Укажите название компании'),
    otherwise: schema => schema.notRequired()
  })
});

Здесь логика проста: если isCompany истинно, поле становится обязательным.


Множественные зависимости в одном условии

Yup позволяет учитывать сразу несколько полей при помощи массива зависимостей:

const schema = Yup.object({
  role: Yup.string(),
  isActive: Yup.boolean(),
  accessCode: Yup.string().when(['role', 'isActive'], {
    is: (role, isActive) => role === 'admin' && isActive,
    then: schema => schema.required(),
    otherwise: schema => schema.notRequired()
  })
});

В этом случае проверка выполняется на основе комбинации значений. Это первый уровень многомерных условий, где логика становится функцией от нескольких переменных.


Цепочки when для последовательной логики

Несколько условий могут быть описаны через последовательное применение when. Каждый следующий вызов расширяет или уточняет предыдущую логику:

const schema = Yup.object({
  type: Yup.string(),
  country: Yup.string(),
  vatNumber: Yup.string()
    .when('type', {
      is: 'business',
      then: schema => schema.required()
    })
    .when('country', {
      is: 'DE',
      then: schema => schema.min(9)
    })
});

Такой подход формирует каскад условий, где каждое правило применяется независимо, но влияет на итоговую валидность поля.


Вложенные условия и контекст объекта

При работе с объектами Yup передаёт весь контекст значения через второй аргумент функции when или через this внутри test.

const schema = Yup.object({
  password: Yup.string(),
  confirmPassword: Yup.string().when('password', (password, schema) =>
    password
      ? schema.required().oneOf([Yup.ref('password')])
      : schema.notRequired()
  )
});

Здесь зависимость выражена не только в факте наличия значения, но и в его содержимом.


Использование test для сложной логики

Когда условий становится слишком много или они не укладываются в декларативный формат when, применяется метод test.

const schema = Yup.object({
  age: Yup.number(),
  hasConsent: Yup.boolean(),
  access: Yup.boolean().test(
    'access-rule',
    'Нет доступа',
    function (value) {
      const { age, hasConsent } = this.parent;

      if (age >= 18 && hasConsent) return true;
      if (age < 18 && value === false) return true;

      return false;
    }
  )
});

test позволяет реализовать произвольные логические выражения, включая вложенные условия, исключения и сложные бизнес-правила.


Эмуляция логических операторов AND / OR

В Yup отсутствуют явные логические операторы, но их можно реализовать через комбинации when и test.

AND-логика:

Yup.string().when(['a', 'b'], {
  is: (a, b) => a && b,
  then: schema => schema.required()
});

OR-логика:

Yup.string().test('or-rule', '', function (value) {
  const { a, b } = this.parent;
  return a || b || !!value;
});

Такие конструкции позволяют моделировать практически любые булевы выражения.


Условная валидация объектов

Множественные условия часто применяются на уровне вложенных структур:

const schema = Yup.object({
  payment: Yup.object({
    method: Yup.string(),
    cardNumber: Yup.string().when('method', {
      is: 'card',
      then: schema => schema.required()
    }),
    paypalEmail: Yup.string().when('method', {
      is: 'paypal',
      then: schema => schema.email().required()
    })
  })
});

Здесь выбор метода оплаты полностью меняет требования к структуре вложенного объекта.


Условия в массивах и динамических структурах

Массивы добавляют дополнительный уровень сложности, поскольку условия могут зависеть от индекса или содержимого элементов:

const schema = Yup.object({
  users: Yup.array().of(
    Yup.object({
      type: Yup.string(),
      license: Yup.string().when('type', {
        is: 'driver',
        then: schema => schema.required()
      })
    })
  )
});

Каждый элемент массива получает собственный контекст валидации, что позволяет задавать локальные правила.


Взаимозависимость нескольких полей

При сложной структуре формы поля часто влияют друг на друга одновременно:

const schema = Yup.object({
  startDate: Yup.date(),
  endDate: Yup.date().when('startDate', (startDate, schema) =>
    startDate
      ? schema.min(startDate)
      : schema
  )
});

Взаимная зависимость формирует связные ограничения, где корректность одного поля определяется другим.


Приоритет условий и порядок применения

При использовании нескольких when важно учитывать порядок их объявления. Каждое последующее условие работает на уже модифицированной схеме. Это означает, что:

  • более ранние правила задают базовую структуру
  • последующие уточняют или переопределяют ограничения
Yup.string()
  .when('a', { is: true, then: s => s.required() })
  .when('b', { is: true, then: s => s.min(5) });

Финальный результат зависит от последовательного применения всех условий.


Особенности работы с контекстом и this

Внутри test доступен контекст this, содержащий:

  • this.parent — объект текущего уровня
  • this.options — параметры схемы
  • this.createError — создание кастомной ошибки

Это позволяет реализовывать многоуровневую логику без ограничения декларативным синтаксисом.


Комбинирование декларативных и императивных подходов

На практике сложные схемы часто строятся гибридно: when используется для простых зависимостей, а test — для объединения нескольких условий, где требуется полный контроль над логикой проверки.

Такой подход позволяет сохранять читаемость схемы и одновременно поддерживать сложные бизнес-правила без разрыва структуры валидации.