Минимальная и максимальная длина массива

Валидация массивов в Yup строится вокруг схемы array(), которая позволяет задавать строгие ограничения на количество элементов, тип содержимого и дополнительные правила. Одними из наиболее часто используемых ограничений являются минимальная и максимальная длина массива, которые реализуются через методы min() и max().

Любая работа с ограничением длины массива начинается с объявления схемы:

import * as Yup fr om 'yup';

const schema = Yup.array();

На этом этапе массив может содержать любое количество элементов. Для практических задач такой вариант почти не используется, поскольку отсутствие ограничений делает данные неконтролируемыми.


Ограничение минимальной длины массива

Метод min() задаёт минимально допустимое количество элементов в массиве. Если массив содержит меньше элементов, чем указано, валидация считается неуспешной.

Синтаксис:

Yup.array().min(lim it, message?)

Пример:

const schema = Yup.array()
  .min(2, 'Необходимо выбрать минимум 2 элемента');

Здесь массив должен содержать не менее двух элементов. Если передан пустой массив или массив с одним элементом, будет возвращена ошибка.

Поведение min()

  • Проверка выполняется строго по длине массива (array.length)
  • Значение null или undefined обрабатывается как пустой массив, если не используется required()
  • Ошибка возвращается только при несоответствии минимальному порогу

Пример использования в контексте формы:

const schema = Yup.object({
  tags: Yup.array()
    .min(1, 'Добавьте хотя бы один тег')
});

Ограничение максимальной длины массива

Метод max() задаёт верхнюю границу количества элементов.

Синтаксис:

Yup.array().max(limit, message?)

Пример:

const schema = Yup.array()
  .max(5, 'Можно выбрать не более 5 элементов');

Если массив содержит больше пяти элементов, валидация не пройдёт.

Поведение max()

  • Сравнение происходит по длине массива
  • Лишние элементы не обрезаются автоматически
  • Ошибка возникает только при превышении лимита

Пример в объекте схемы:

const schema = Yup.object({
  categories: Yup.array()
    .max(3, 'Допустимо выбрать максимум 3 категории')
});

Одновременное использование min и max

Наиболее распространённый сценарий — комбинирование минимального и максимального ограничения.

const schema = Yup.array()
  .min(2, 'Выберите минимум 2 элемента')
  .max(4, 'Можно выбрать не более 4 элементов');

Такая схема задаёт диапазон допустимых значений длины массива.

Логика проверки

  • Сначала проверяется минимальное ограничение
  • Затем максимальное
  • Ошибка возвращается по первому нарушенному правилу

Влияние required() на min и max

Метод required() влияет на трактовку пустых значений.

const schema = Yup.array()
  .required('Поле обязательно')
  .min(1, 'Нужно выбрать хотя бы один элемент');

Разница между required() и min(1):

  • required() запрещает undefined и null
  • min(1) допускает существование массива, но требует минимум один элемент

Комбинация этих методов часто используется для строгой проверки заполнения:

Yup.array()
  .required()
  .min(1)

Кастомные сообщения и интерполяция параметров

Yup позволяет использовать динамические сообщения об ошибках с параметрами через шаблонные строки.

const schema = Yup.array()
  .min(2, ({ min }) => `Требуется минимум ${min} элемента`)
  .max(5, ({ max }) => `Допустимо максимум ${max} элементов`);

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


Валидация массива объектов с ограничением длины

Ограничения min и max применяются не только к примитивным массивам, но и к массивам объектов.

const schema = Yup.object({
  participants: Yup.array()
    .of(
      Yup.object({
        name: Yup.string().required(),
        age: Yup.number().required()
      })
    )
    .min(2, 'Нужно минимум 2 участника')
    .max(10, 'Максимум 10 участников')
});

Здесь проверяется не только структура каждого элемента, но и общее количество элементов массива.


Ленивые схемы и динамическая длина

В некоторых случаях ограничения могут зависеть от внешних условий.

const schema = Yup.object({
  isAdmin: Yup.boolean(),
  users: Yup.array().when('isAdmin', {
    is: true,
    then: schema => schema.min(5, 'Администратор должен выбрать минимум 5 пользователей'),
    otherwise: schema => schema.max(2, 'Ограниченный доступ: максимум 2 пользователя')
  })
});

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


Поведение при пустых значениях

Важно учитывать различие между:

  • undefined
  • null
  • []

Пример:

Yup.array().min(1)
  • undefined → ошибка (если нет required(false))
  • null → ошибка
  • [] → ошибка
  • [item] → проходит

Внутренний механизм проверки длины

При валидации Yup приводит входное значение к массиву (если возможно) и проверяет свойство length.

Упрощённо логика выглядит так:

if (value.length < min) {
  throw error;
}

if (value.length > max) {
  throw error;
}

При этом сами элементы массива не анализируются в рамках min/max, только их количество.


Частые ошибки при использовании min и max

1. Отсутствие of()

Хотя min/max работают без of(), при работе со сложными структурами часто забывают указать тип элементов:

Yup.array().min(2)

Это допустимо, но не гарантирует типизацию элементов.

2. Конфликт required и min

Yup.array().required().min(0)

Такой код избыточен: min(0) всегда истинно для массива.

3. Неверное ожидание обрезки массива

Yup не изменяет данные:

Yup.array().max(3)

Если передать 10 элементов, они не будут обрезаны — произойдёт ошибка.


Практический пример формы

const validationSchema = Yup.object({
  skills: Yup.array()
    .of(Yup.string().required())
    .min(1, 'Добавьте хотя бы один навык')
    .max(5, 'Не более пяти навыков')
});

Комбинация с transform()

Иногда требуется нормализовать данные перед проверкой:

const schema = Yup.array()
  .transform((value, originalValue) => {
    if (typeof originalValue === 'string') {
      return originalValue.split(',').map(item => item.trim());
    }
    return value;
  })
  .min(2)
  .max(5);

Такой подход полезен при работе с вводом строкового списка.


Поведение в асинхронной валидации

min и max являются синхронными проверками и выполняются до любых test() с асинхронной логикой:

Yup.array()
  .min(1)
  .test('check-db', 'Ошибка проверки', async value => {
    return await checkServer(value);
  });

Итоговая модель поведения min/max

  • min(n) — проверяет, что length >= n
  • max(n) — проверяет, что length <= n
  • Не изменяют данные
  • Работают только с длиной массива
  • Применяются до кастомных тестов
  • Совместимы с of(), required(), when(), transform()