Схема массива в Yup строится вокруг базового метода
array(), который позволяет описывать структуру и
ограничения для массивов любой сложности: от простых списков строк до
вложенных коллекций объектов с многоуровневой валидацией.
Основная идея заключается в том, что массив рассматривается не как абстрактная структура, а как контейнер с элементами определённого типа, каждый из которых может проходить собственную схему проверки.
Схема массива создаётся через Yup.array():
import * as Yup from 'yup';
const schema = Yup.array();
Такое объявление само по себе не накладывает ограничений на
содержимое массива. Любые значения, включая undefined и
null, будут допустимы, если не добавлены дополнительные
правила.
Ключевой метод — of(), который задаёт схему для каждого
элемента массива:
const schema = Yup.array().of(
Yup.string()
);
В этом случае массив должен содержать только строки. Любое несоответствие типу приведёт к ошибке валидации.
Пример допустимых данных:
schema.validate(['a', 'b', 'c']);
Пример недопустимых данных:
schema.validate(['a', 2, true]);
Для указания обязательного массива используется
required():
const schema = Yup.array().of(
Yup.number()
).required();
Теперь значение undefined или null будет
считаться ошибкой, даже если структура элементов корректна.
Yup предоставляет методы для контроля размера массива:
Yup.array().min(2);
Yup.array().max(5);
Yup.array().length(3);
Эти ограничения часто применяются в формах, где количество элементов строго регламентировано, например список контактов или выбор вариантов.
Метод unique отсутствует в базовом Yup, но реализуется
через test():
const schema = Yup.array().test(
'unique',
'Элементы массива должны быть уникальными',
(value) => {
if (!value) return true;
return new Set(value).size === value.length;
}
);
Такой подход сравнивает длину массива с количеством уникальных значений.
Наиболее распространённый сценарий — массив объектов с собственной схемой:
const itemSchema = Yup.object({
id: Yup.number().required(),
name: Yup.string().required()
});
const schema = Yup.array().of(itemSchema);
Пример данных:
[
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
Любое нарушение структуры объекта внутри массива приведёт к ошибке именно на уровне элемента, а не всего массива.
Yup позволяет строить многоуровневые структуры:
const schema = Yup.array().of(
Yup.array().of(
Yup.number().required()
)
);
Такой подход используется для матриц, таблиц и сложных структур данных.
При необходимости допускается использование mixed():
const schema = Yup.array().of(
Yup.mixed()
);
Это отключает строгую типизацию, но позволяет добавлять проверки
через test():
const schema = Yup.array().of(
Yup.mixed().test('is-valid', 'Недопустимое значение', (value) => {
return typeof value === 'string' || typeof value === 'number';
})
);
Метод test() внутри of() позволяет
реализовать кастомную логику:
const schema = Yup.array().of(
Yup.number().test(
'positive',
'Число должно быть положительным',
(value) => value > 0
)
);
Каждый элемент проходит проверку независимо.
Условная логика позволяет менять схему массива в зависимости от внешних данных:
const schema = Yup.array().when('type', {
is: 'numbers',
then: Yup.array().of(Yup.number()),
otherwise: Yup.array().of(Yup.string())
});
Такой подход часто используется в динамических формах.
Метод transform() позволяет нормализовать входные
значения:
const schema = Yup.array().transform((value) => {
if (typeof value === 'string') {
return value.split(',');
}
return value;
});
Это полезно при обработке строковых вводов, которые должны интерпретироваться как массив.
Пустые массивы часто требуют отдельной обработки:
Yup.array()
.of(Yup.string())
.min(1, 'Массив не должен быть пустым');
Также можно явно разрешать пустое значение:
Yup.array().nullable();
При использовании test() возможно выполнение асинхронных
проверок:
const schema = Yup.array().of(
Yup.string().test(
'exists',
'Значение не найдено',
async (value) => {
const result = await fakeApiCheck(value);
return result === true;
}
)
);
Каждый элемент обрабатывается независимо, но с учётом асинхронного потока.
Yup поддерживает вывод типов:
import * as Yup from 'yup';
const schema: Yup.ArraySchema<string[]> = Yup.array().of(
Yup.string().required()
);
Для объектов:
type User = {
id: number;
name: string;
};
const schema: Yup.ArraySchema<User[]> = Yup.array().of(
Yup.object({
id: Yup.number().required(),
name: Yup.string().required()
})
);
Ошибки валидации массива могут быть:
Пример:
[0].name must be a string
Это позволяет точно определить проблемный элемент без необходимости ручного анализа структуры.
Схемы можно переиспользовать:
const stringArray = Yup.array().of(Yup.string());
const emailArray = Yup.array().of(
Yup.string().email()
);
Это упрощает поддержку больших проектов и снижает дублирование логики.
При работе с вложенными массивами и сложными объектами важно
учитывать стоимость валидации. Каждое of() создаёт
отдельный уровень обхода структуры данных, что при больших объёмах может
влиять на производительность.
Пример глубокой структуры:
Yup.array().of(
Yup.object({
tags: Yup.array().of(
Yup.object({
value: Yup.string().required()
})
)
})
);
Такие схемы требуют аккуратного проектирования, особенно при работе с динамическими формами и большими датасетами.
В сложных случаях массивы комбинируются с lazy() для
динамического определения структуры:
const schema = Yup.array().of(
Yup.lazy((value) => {
if (typeof value === 'string') {
return Yup.string().min(3);
}
return Yup.number().positive();
})
);
Это позволяет изменять поведение схемы в зависимости от конкретного значения элемента.
Массивы часто используются внутри объектов:
const schema = Yup.object({
users: Yup.array().of(
Yup.object({
id: Yup.number().required(),
roles: Yup.array().of(Yup.string())
})
)
});
Такая структура характерна для API-ответов и сложных форм состояния приложения.