Несоответствие формы и схемы Yup является одной из самых частых причин некорректной работы YupResolver в связке с React Hook Form. Схема описывает структуру данных строго, тогда как форма часто содержит упрощённые или частично заполненные значения. При несовпадении ключей или типов Yup начинает возвращать ошибки, которые на первый взгляд кажутся «рандомными».
Основная проблема возникает, когда поля формы и поля схемы имеют разные уровни вложенности или разные имена.
const schema = yup.object({
user: yup.object({
email: yup.string().email().required()
})
});
const { register } = useForm({
resolver: yupResolver(schema)
});
// Ошибка: форма использует "email", а схема ожидает "user.email"
<input {...register("email")} />
В подобных случаях YupResolver корректно валидирует структуру схемы, но форма передаёт данные в другой форме, из-за чего ошибки либо не отображаются, либо отображаются не там, где ожидается.
Ошибки часто возникают при неправильной передаче resolver или импорте несовместимых версий библиотек.
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
Проблемы появляются при:
@hookform/resolversВ результате валидатор может не запускаться или возвращать пустой
errors объект.
При использовании YupResolver в TypeScript часто возникает несоответствие типов между схемой и формой. Это приводит к тому, что ошибки типизации скрывают реальные проблемы в рантайме.
const schema = yup.object({
age: yup.number().required()
});
type FormData = yup.InferType<typeof schema>;
Типичная ошибка — ручное объявление интерфейса, который расходится со схемой:
type FormData = {
age: string; // ошибка: должно быть number
};
В таком случае YupResolver корректно валидирует число, но форма ожидает строку, что приводит к постоянным ошибкам преобразования.
Одной из скрытых проблем является создание Yup-схемы внутри компонента. Это приводит к тому, что resolver получает новую ссылку на схему при каждом рендере.
function Form() {
const schema = yup.object({
name: yup.string().required()
});
const form = useForm({
resolver: yupResolver(schema)
});
}
Последствия:
Правильный подход — вынос схемы за пределы компонента.
YupResolver не исправляет несоответствие между
defaultValues и схемой. Если начальные значения отсутствуют
или имеют неправильный тип, Yup начинает интерпретировать их как
undefined.
const form = useForm({
defaultValues: {
age: ""
},
resolver: yupResolver(schema)
});
При схеме:
age: yup.number().required()
возникает конфликт: пустая строка не приводится автоматически к числу без дополнительной настройки.
Yup по умолчанию пытается приводить типы, что может неожиданно влиять на результат валидации.
age: yup.number().transform((value, originalValue) => {
return originalValue === "" ? undefined : value;
})
Без подобных трансформаций часто возникают ошибки:
undefinedNaN после преобразования.required()По умолчанию Yup может возвращать только первую ошибку валидации, что создаёт иллюзию «неполной проверки».
yup.object({
email: yup.string().email().required()
}).validate(data, { abortEarly: false });
При использовании YupResolver важно учитывать, что агрегирование
ошибок влияет на структуру formState.errors, особенно при
вложенных объектах.
Работа с массивами и объектами является источником сложных ошибок.
const schema = yup.object({
users: yup.array().of(
yup.object({
email: yup.string().required()
})
)
});
Типичные проблемы:
key в динамических списках ReactfieldArray без синхронизации
схемыYupResolver возвращает ошибки с глубокой вложенностью, что требует корректного маппинга в UI.
Метод when часто используется неправильно, особенно при
попытке зависеть от внешних полей формы.
password: yup.string().when("hasPassword", {
is: true,
then: yup.string().required()
});
Ошибки возникают, когда:
В таких случаях resolver может некорректно пересчитывать схему.
Семантика Yup часто приводит к путанице:
required() — запрещает undefinednullable() — допускает nullundefinedyup.string().nullable().required()
Такая комбинация может вести к неожиданному поведению:
null допускается, но пустая строка — нет.
При больших формах с десятками полей YupResolver может стать узким местом.
Причины:
Особенно заметно при режиме mode: "onChange" в React
Hook Form.
Распространённая проблема — использование несовместимых версий:
react-hook-form v6/v7@hookform/resolvers разных поколенийyup 0.32 vs 1.xСимптомы:
YupResolver тесно связан с режимами:
useForm({
mode: "onBlur",
resolver: yupResolver(schema)
});
Неправильный выбор режима приводит к:
Особенно проблемным является смешивание onSubmit и
onChange поведения.
Yup может возвращать очищенные данные, но при отсутствии настройки
stripUnknown валидация не удаляет лишние поля.
yup.object().noUnknown(true)
Без этого в форму могут попадать:
Это влияет на стабильность resolver и итоговые данные submit.