Работа с массивами в схемах валидации строится вокруг типа
array, который в Yup является одним из базовых контейнеров
для описания коллекций данных. В связке с
@hookform/resolvers/yup массивы приобретают особую
значимость, поскольку именно через них чаще всего моделируются
динамические формы: списки товаров, наборы тегов, участники, шаги,
адреса и любые повторяющиеся структуры.
Конструкция массива в Yup задаётся через yup.array(). На
этом уровне определяется сам факт того, что значение должно быть
массивом, без уточнения структуры элементов.
import * as yup from "yup";
const schema = yup.object({
tags: yup.array()
});
Такое описание гарантирует лишь одно: поле tags должно
быть массивом. Однако элементы массива при этом остаются
неограниченными, и любая строка, объект или число будет считаться
допустимым значением внутри.
Для реальных сценариев этого недостаточно, поэтому следующим шагом становится определение типа элементов.
ofМетод of задаёт схему для каждого элемента массива. Это
ключевой механизм, позволяющий превращать массив в строго типизированную
структуру.
const schema = yup.object({
tags: yup.array().of(yup.string())
});
Теперь каждый элемент массива обязан быть строкой. Любое несоответствие приведёт к ошибке валидации.
Аналогично можно задавать массивы чисел:
const schema = yup.object({
scores: yup.array().of(yup.number())
});
При интеграции с YupResolver это особенно важно, так как ошибки
формируются на уровне индексов массива и передаются в
react-hook-form с точной привязкой к позиции элемента.
Массивы часто требуют контроля размера. Для этого используются методы
min, max и length.
const schema = yup.object({
tags: yup.array().of(yup.string()).min(1).max(5)
});
В этом случае массив должен содержать минимум один элемент и максимум пять. Если нарушается одно из условий, ошибка привязывается к самому полю массива, а не к конкретному элементу.
Метод length задаёт строго фиксированную длину:
const schema = yup.object({
code: yup.array().of(yup.number()).length(4)
});
Такая конструкция часто применяется для кодов подтверждения, сегментированных идентификаторов или фиксированных наборов параметров.
По умолчанию массив может отсутствовать или быть
undefined. Для строгой формы используется
required:
const schema = yup.object({
tags: yup.array().of(yup.string()).required()
});
Если поле не передано вовсе, валидация провалится. Однако важно
учитывать, что пустой массив ([]) при этом считается
валидным значением. Это частая особенность, влияющая на бизнес-логику
форм.
Для запрета пустых массивов применяется комбинация
required и min(1):
tags: yup.array().of(yup.string()).required().min(1)
На практике наиболее распространённый сценарий — массив объектов. Это основа динамических списков форм.
const schema = yup.object({
users: yup.array().of(
yup.object({
name: yup.string().required(),
age: yup.number().min(18).required()
})
)
});
Каждый элемент массива представляет собой объект с собственной схемой. YupResolver в этом случае формирует вложенные ошибки вида:
users[0].nameusers[1].ageТакая структура напрямую соответствует механике
react-hook-form, что обеспечивает точную привязку ошибок к
полям интерфейса.
Yup поддерживает произвольную глубину вложенности, включая массивы внутри массивов. Это важно для сложных моделей данных, таких как матрицы, таблицы или структурированные опросники.
const schema = yup.object({
matrix: yup.array().of(
yup.array().of(yup.number())
)
});
Здесь каждый элемент верхнего массива сам является массивом чисел. Ошибки валидации будут содержать двухуровневую индексацию:
matrix[0][2]Такая структура требует аккуратного управления в UI, так как любая ошибка должна быть сопоставлена с конкретной ячейкой.
testИногда стандартных методов недостаточно, и требуется кастомная
логика. Для этого используется test.
const schema = yup.object({
ids: yup.array().of(yup.number()).test(
"unique",
"Элементы массива должны быть уникальными",
(value) => {
if (!value) return true;
return new Set(value).size === value.length;
}
)
});
Здесь реализуется проверка уникальности значений. Такая логика не входит в стандартные методы Yup, но легко интегрируется через кастомные тесты.
nullable и
defaultМассивы часто взаимодействуют с состояниями отсутствия данных.
nullable позволяет явно разрешить null:
tags: yup.array().of(yup.string()).nullable()
В таком случае допустимы три состояния:
nullrequired)Метод default позволяет задавать начальное значение:
tags: yup.array().of(yup.string()).default([])
Это особенно важно в связке с YupResolver, поскольку React Hook Form ожидает определённую структуру данных при инициализации формы. Отсутствие массива может приводить к ошибкам при рендере динамических списков.
Метод transform используется для нормализации входных
данных перед валидацией.
tags: yup.array().of(yup.string()).transform((value) => {
if (typeof value === "string") {
return value.split(",");
}
return value;
})
Такая конструкция полезна при работе с формами, где данные могут приходить в несогласованном формате, например из текстового поля.
mixedYup позволяет создавать массивы с неоднородными типами через
mixed, хотя это требует осторожности.
const schema = yup.object({
values: yup.array().of(yup.mixed())
});
В этом случае внутри массива могут находиться значения любого типа. Однако при использовании YupResolver это усложняет обработку ошибок и снижает предсказуемость структуры формы.
Более контролируемый подход — использование oneOf или
кастомных тестов внутри mixed.
При подключении схемы к react-hook-form через
yupResolver массивы начинают играть ключевую роль в
синхронизации состояния формы и валидации.
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
const form = useForm({
resolver: yupResolver(schema)
});
При изменении массива React Hook Form передаёт обновлённое значение в Yup, который выполняет валидацию всей структуры целиком или частично, в зависимости от режима.
Ошибки возвращаются в виде вложенного объекта:
{
users: [
{ name: "Ошибка" },
{ age: "Слишком мало" }
]
}
Это позволяет точно отображать ошибки в динамических списках.
Хотя Yup отвечает за валидацию, управление длиной массива обычно
реализуется через useFieldArray из React Hook Form. Однако
схема Yup должна быть заранее готова к динамическому изменению
структуры.
users: yup.array().of(
yup.object({
name: yup.string().required()
})
)
При добавлении или удалении элементов схема не меняется, что обеспечивает стабильную валидацию независимо от размера массива.
Одной из ключевых особенностей работы массивов является способ формирования ошибок. Индексация строго соответствует позиции элемента.
[0][1]При вложенных структурах индексация расширяется:
items[0].subItems[2].valueТакая система требует согласованности между UI и схемой, иначе отображение ошибок становится некорректным.
Массивы могут содержать «дыры» — пропущенные индексы. Yup по умолчанию игнорирует такие особенности JavaScript, но при необходимости можно учитывать их через кастомные проверки.
yup.array().of(yup.string().required())
Если элемент отсутствует, он будет интерпретирован как
undefined, что вызовет ошибку при наличии
required.
Массивы часто требуют комплексной валидации, где одновременно применяются ограничения на элементы и саму коллекцию:
yup.array()
.of(yup.number().min(0).max(100))
.min(3)
.max(10)
.required()
Здесь контролируется:
Такая композиция позволяет моделировать строгие бизнес-правила без дополнительной логики вне схемы.
В большинстве реальных интерфейсов массивы выступают фундаментом
структурирования данных. Списки товаров, адресов, телефонов,
комментариев и вложенных сущностей строятся именно через
yup.array().of(...).
При использовании YupResolver это обеспечивает единый слой валидации, который не зависит от UI-логики и сохраняет консистентность данных при любом количестве элементов и уровнях вложенности.