Breaking changes между версиями

В экосистеме React Hook Form резолвер YupResolver претерпевал изменения, связанные с развитием как самой библиотеки Yup, так и архитектуры валидационных резолверов. Эти изменения затрагивали сигнатуры функций, поведение асинхронной валидации, обработку ошибок и типизацию в TypeScript, что в совокупности приводило к необходимости адаптации кода при переходе между версиями.

Ранние версии YupResolver опирались на относительно прямолинейную схему преобразования схемы Yup в формат ошибок React Hook Form. Основная идея заключалась в вызове schema.validate(values) и последующем маппинге ошибок.

Позднее модель была переработана в сторону унификации с другими резолверами:

  • переход на единый интерфейс Resolver<T>
  • стандартизация возвращаемого объекта { values, errors }
  • поддержка контекста и параметров валидации React Hook Form

Ключевое изменение: обработка Yup-ошибок перестала быть «встроенной логикой» и стала частью адаптера.

Переход от синхронной обработки к полной асинхронности

Одним из наиболее заметных изменений стало усиление роли асинхронной валидации.

Ранние реализации допускали частично синхронное поведение при отсутствии асинхронных правил в Yup-схеме. Позднее это было устранено:

  • validate() всегда возвращает Promise
  • убрана возможность синхронного возврата результатов
  • унифицировано поведение для всех схем Yup

Это изменение повлияло на интеграцию с React Hook Form, где теперь любые вызовы resolver обрабатываются как асинхронные вне зависимости от сложности схемы.

Изменения в сигнатуре yupResolver

Сигнатура функции yupResolver изменялась несколько раз, что является одной из основных причин несовместимости версий.

Ранний формат

yupResolver(schema)

Простой вызов без дополнительных параметров.

Промежуточные версии

Добавление контекста и опций:

yupResolver(schema, options)

Где options включали:

  • context
  • abortEarly
  • stripUnknown

Современный формат

yupResolver(schema, options?, resolverOptions?)

Появился третий аргумент, связанный с React Hook Form resolver options:

  • режим валидации (mode)
  • критерии повторной валидации
  • поведение при unmount полей

Критическое изменение: перенос части конфигурации из Yup-уровня в уровень интеграции с формой.

Изменения в обработке ошибок Yup

Одним из самых чувствительных изменений стала переработка структуры ошибок.

Старое поведение

Ошибки формировались в упрощённом виде:

{
  fieldName: {
    type: "validation",
    message: "Error message"
  }
}

Новое поведение

Структура стала более унифицированной с React Hook Form:

{
  type?: string;
  message?: string;
  ref?: any;
}

Дополнительно:

  • поддержка вложенных объектов ошибок
  • корректная обработка массивов (array fields)
  • нормализация путей Yup (path → RHF field name)

Суть изменения: отказ от упрощённого маппинга в пользу полной совместимости с системой ошибок формы.

Изменения в работе с abortEarly

Поведение abortEarly в Yup претерпело важную эволюцию.

Ранее

  • значение часто задавалось внутри Yup-схемы
  • резолвер мог переопределять поведение локально

Позднее

  • приоритет получил единый источник конфигурации
  • резолвер перестал неявно изменять поведение схемы
  • добавлена более строгая предсказуемость результата

Это привело к следующему:

  • уменьшение неожиданного «обрезания» ошибок
  • более стабильная отладка форм
  • необходимость явного контроля стратегии валидации

Изменения типизации TypeScript

Существенный пласт breaking changes связан с TypeScript.

Ужесточение generic-типов

Ранее:

Resolver<T>

Позднее:

Resolver<TFieldValues, TContext>

Добавился контекст формы как отдельный generic-параметр.

Улучшение типизации ошибок

  • FieldErrors<T> стал строго связан с ключами формы
  • добавлена поддержка вложенных типов
  • улучшена работа с массивами (FieldArray)

Практический эффект: меньше неявных any, но больше требований к точности описания схемы формы.

Изменения в совместимости с Yup

С ростом версии Yup часть breaking changes была обусловлена не самим резолвером, а изменениями в Yup API.

Основные точки несовместимости

  • изменение поведения ValidationError.inner
  • усиление строгой валидации типов
  • различия в работе кастомных тестов (test())
  • изменение обработки nullable() и required()

YupResolver адаптировался к этим изменениям через:

  • переработку парсинга ValidationError
  • унификацию обработки path
  • нормализацию сообщений об ошибках

Изменения стратегии трансформации значений

В новых версиях изменился подход к обработке cast и transform:

  • ранее трансформация могла происходить неявно до валидации
  • позже поведение стало более детерминированным
  • добавлено разделение: transform → validate → output mapping

Это повлияло на:

  • порядок выполнения логики схемы
  • итоговые значения формы
  • согласованность с React Hook Form state

Изменения поведения при nested fields

Работа с вложенными структурами (user.address.street) претерпела несколько улучшений:

  • унификация path mapping между Yup и RHF
  • корректная обработка отсутствующих промежуточных объектов
  • поддержка глубоких массивов объектов

Ранее частыми проблемами были:

  • потеря ошибок на глубоком уровне
  • некорректное сопоставление индексов массивов
  • несовпадение структуры Yup и формы

Поздние версии решают это через более строгую нормализацию путей.

Изменения в производительности

Оптимизации затронули:

  • кеширование схем Yup
  • уменьшение повторных validate() вызовов
  • оптимизацию маппинга ошибок

Основные изменения:

  • отказ от лишних рекурсивных обходов
  • более эффективная обработка abortEarly=false
  • снижение количества промежуточных объектов

Изменения поведения при re-validation

В более ранних версиях наблюдалось:

  • избыточное повторное выполнение полной схемы
  • отсутствие дифференциации изменённых полей

Позднее появились улучшения:

  • частичная валидация при изменении поля
  • более тесная интеграция с режимами React Hook Form (onChange, onBlur)
  • оптимизация повторных вычислений

Изменения API совместимости с React Hook Form

YupResolver стал более строго следовать контракту React Hook Form:

  • стандартизированное возвращение { values, errors }
  • поддержка shouldUseNativeValidation
  • корректная работа с criteriaMode: "all"

Также изменилось поведение при:

  • unmount полей
  • динамических формах
  • reset формы

Каждое из этих изменений направлено на предсказуемость состояния формы при сложных сценариях управления UI.