YupResolver представляет собой адаптер, обеспечивающий
интеграцию схем валидации Yup с библиотеками управления формами, прежде
всего с React Hook Form. Основная задача слоя resolver — преобразование
результата валидации схемы в унифицированный формат ошибок, понятный
форме.
В контексте миграции ключевым становится не только синтаксис схем, но и поведенческая модель: синхронная и асинхронная валидация, структура ошибок, кастомные трансформации данных и стратегия выполнения валидации (onChange, onBlur, onSubmit).
Переход на YupResolver затрагивает несколько слоёв логики:
1. Структура схемы
string().required().min())2. Модель ошибок
path)3. Асинхронность
test(async () => {})4. Трансформация данных
transform() в Yup заменяет post-processing в кастомных
схемахZod и Yup концептуально схожи, но различаются подходом к типизации и композиции схем.
// Zod
const schema = z.object({
email: z.string().email(),
age: z.number().min(18)
});
// Yup
import * as yup from 'yup';
const schema = yup.object({
email: yup.string().email().required(),
age: yup.number().min(18).required()
});
1. Strict parsing vs coercion
Решение при миграции:
age: yup.number().transform(value => Number(value))
2. Optional/nullable
.optional(), .nullable().notRequired(), .nullable()3. Error mapping Zod возвращает структурированные
issues, Yup — ValidationError с inner[].
React Hook Form resolver:
import { yupResolver } from '@hookform/resolvers/yup';
Joi ориентирован на серверную валидацию и более декларативен в стиле описания схем.
// Joi
const schema = Joi.object({
username: Joi.string().min(3).required(),
age: Joi.number().min(18)
});
// Yup
const schema = yup.object({
username: yup.string().min(3).required(),
age: yup.number().min(18)
});
1. Сообщения об ошибках
message аргументыyup.string().required('Поле обязательно')
2. Рекурсивные структуры Joi поддерживает более сложные описания вложенных схем, но Yup проще интегрируется с фронтендом.
3. AbortEarly
abortEarly: falseabortEarly: false в validateschema.validate(data, { abortEarly: false });
Многие проекты используют собственные функции:
function validate(values) {
const errors = {};
if (!values.email) errors.email = 'required';
return errors;
}
1. Простые проверки
email: yup.string().email().required()
2. Сложные правила через test
password: yup.string().test(
'password-strength',
'Слабый пароль',
value => /[A-Z]/.test(value) && /[0-9]/.test(value)
)
3. Зависимые поля
confirmPassword: yup
.string()
.oneOf([yup.ref('password')], 'Пароли не совпадают')
Основной сценарий миграции связан с заменой ручной валидации на resolver.
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
const form = useForm({
resolver: yupResolver(schema)
});
React Hook Form ожидает:
{
fieldName: {
type: string,
message: string
}
}
YupResolver преобразует:
ValidationError -> RHFErrorMap
username: yup.string().test(
'unique',
'Уже существует',
async value => {
const res = await api.checkUsername(value);
return res.available;
}
)
const schema = yup.object({
user: yup.object({
name: yup.string().required(),
address: yup.object({
city: yup.string().required()
})
})
});
items: yup.array().of(
yup.object({
id: yup.number(),
title: yup.string().required()
})
)
Yup может преобразовывать строки в числа:
yup.number().required()
Решение:
strict: true
yup.string().trim().required()
При переходе с кастомных валидаторов часто теряется:
Решение — использование inner массива
ValidationError.
TypeScript схемы Zod не конвертируются напрямую в Yup — требуется ручное пересоздание.
resolver: async (values) => {
try {
await yupSchema.validate(values);
} catch (e) {
return zodCompatibleMapper(e);
}
}
Вынос схем в отдельный модуль:
/validation
yup/
zod/
joi/
useMemoconst schema = useMemo(() => yup.object({...}), []);
test()abortEarly: true для быстрых форм| Функция | Zod | Joi | Custom | Yup |
|---|---|---|---|---|
| Strict typing | +++ | + | - | + |
| Frontend integration | ++ | + | + | +++ |
| Async validation | ++ | + | +++ | +++ |
| Schema readability | ++ | + | + | +++ |