В основе работы YupResolver лежит преобразование результата валидации
схемы Yup в единый формат ошибок, который понимает React Hook Form.
Программная обработка ошибок строится вокруг нормализации структуры
ValidationError в объект вида:
errors: объект с ключами полей формыvalues: валидированные данные (или частично
валидированные)criteriaMode: режим группировки ошибокКлючевая задача резолвера — превратить сложную, вложенную иерархию ошибок Yup в плоскую структуру, пригодную для UI-рендеринга и программной обработки.
Yup возвращает ошибки в виде экземпляра ValidationError,
который может содержать:
path — путь до поля (например
user.email)message — текст ошибкиinner — массив вложенных ошибок (при
abortEarly: false)Пример:
import * as yup from "yup";
const schema = yup.object({
user: yup.object({
email: yup.string().email().required(),
age: yup.number().min(18),
}),
});
При валидации с несколькими ошибками inner может
выглядеть так:
[
{ path: "user.email", message: "Invalid email" },
{ path: "user.age", message: "Must be at least 18" }
]
YupResolver выполняет следующие шаги:
schema.validate(data, { abortEarly: false })ValidationErrorinnerРезультат:
{
user: {
email: { type: "validation", message: "Invalid email" },
age: { type: "validation", message: "Must be at least 18" }
}
}
Флаг abortEarly критически влияет на программную
обработку ошибок.
inner может быть пустымschema.validate(data, { abortEarly: true });
Поведение YupResolver в этом режиме:
innerschema.validate(data, { abortEarly: false });
Это основной режим для YupResolver, так как он позволяет:
Пути (path) в Yup могут быть:
emailuser.emailitems[0].nameYupResolver обязан преобразовать их в структуру, совместимую с React Hook Form.
{
"user.email": "error"
}
преобразуется в:
{
user: {
email: { message: "error", type: "validation" }
}
}
items[2].name
становится:
{
items: [
null,
null,
{
name: { message: "error" }
}
]
}
Ключевая сложность здесь — сохранение индексов без потери структуры массива.
YupResolver формирует FieldErrors через рекурсивный
разбор path.
Алгоритм:
. и []Пример внутреннего представления:
{
_errors: ["global message"],
user: {
email: {
_errors: ["Invalid email"]
}
}
}
При множественных ошибках одного поля возникает необходимость агрегации.
Последняя ошибка перезаписывает предыдущую:
email: "Must be valid"
email: "Required"
Итог:
email: "Required"
email: ["Must be valid", "Required"]
Используется при criteriaMode: "all".
В React Hook Form параметр criteriaMode влияет на
структуру ошибок.
email: {
types: {
required: "Email is required",
pattern: "Invalid format"
}
}
YupResolver должен преобразовать Yup-ошибки в этот формат через
группировку по path.
Yup поддерживает асинхронную валидацию:
yup.string().test("check-db", async (value) => {
return await checkEmail(value);
});
YupResolver должен:
ValidationErrorПрограммная логика:
try {
await schema.validate(data, { abortEarly: false });
} catch (err) {
if (err instanceof ValidationError) {
return mapErrors(err);
}
}
Yup позволяет генерировать кастомные ошибки:
throw new yup.ValidationError("Custom error", value, "field");
YupResolver должен:
messagepathvalueИногда ошибки не имеют пути:
Решение:
errors._root = { message }
user.email.error
user[email]
Требуется унификация через нормализацию токенов.
Если поле ожидает number, но приходит строка:
type: "typeError"При больших формах (100+ полей):
innerПри конфликте нескольких источников ошибок:
приоритет:
Финальный объект должен соответствовать контракту:
{
values: TFieldValues,
errors: FieldErrors<TFieldValues>
}
YupResolver обязан гарантировать:
В TypeScript контексте:
FieldError = {
type: string;
message?: string;
ref?: Ref;
};
YupResolver приводит все ошибки к единому виду:
type: "validation"message: stringrefФормально процесс можно описать как функцию:
YupValidationError → normalize(path, message, inner) → FieldErrors
С промежуточными этапами:
Yup может вернуть валидные данные даже при наличии ошибок.
YupResolver разделяет:
values — частично валидные данныеerrors — блокирующие ошибкиЭто позволяет: