Переход с версии 0.x на 1.x

Yup версии 1.x принесла ряд изменений, которые затронули как внутреннюю архитектуру, так и публичный API. Переход с 0.x требует внимательного пересмотра схем валидации, обработки ошибок и типизации, поскольку часть привычных методов была изменена или переосмыслена.

В версии 0.x схемы часто строились вокруг цепочек методов, которые могли комбинироваться без строгого контроля контекста. В 1.x акцент смещён в сторону более явной и предсказуемой декларативности.

Одним из ключевых изменений стало усиление роли базовых схем:

  • string(), number(), boolean() стали более строгими в обработке входных значений
  • преобразование типов теперь явно контролируется через transform
  • неявные касты данных стали менее агрессивными

Пример различий:

// 0.x (поведение более "гибкое")
Yup.string().required().email()

// 1.x (поведение более строгое и предсказуемое)
Yup.string()
  .strict(true)
  .required()
  .email()

Изменения в валидации объектов

Работа с object() стала более детализированной. В 0.x часто допускалась частичная валидация без строгого контроля вложенных схем. В 1.x поведение изменилось в сторону полной иерархической проверки.

const schema = Yup.object({
  user: Yup.object({
    name: Yup.string().required(),
    age: Yup.number().min(18)
  })
});

В 1.x важно учитывать, что:

  • вложенные схемы всегда проходят собственный цикл валидации
  • undefined больше не игнорируется по умолчанию в некоторых контекстах
  • требуется явное управление default() значениями

Изменения обработки nullable и optional значений

Одно из заметных изменений — пересмотр логики nullable() и defined().

В 0.x null часто проходил через валидацию без дополнительных условий. В 1.x это поведение стало более контролируемым.

Yup.string()
  .nullable()
  .defined()

Теперь:

  • nullable() разрешает null, но не undefined
  • defined() запрещает оба варианта отсутствия значения
  • комбинация этих методов влияет на строгую типизацию результата

Изменения методов трансформации данных

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

Yup.number().transform((value, originalValue) => {
  return originalValue === "" ? null : value;
});

В версии 1.x важно учитывать:

  • трансформация выполняется до основной валидации
  • результат transform влияет на все последующие проверки
  • цепочки transform больше не могут “перепрыгивать” типы без явного преобразования

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

array() получил более строгую модель проверки элементов.

Yup.array()
  .of(Yup.number().required())
  .min(1)

Ключевые отличия от 0.x:

  • каждый элемент проходит полную валидацию схемы
  • ошибки теперь агрегируются более структурировано
  • поведение compact() и фильтрации стало менее неявным

Изменения в системе ошибок

В 1.x переработан формат ошибок валидации:

  • ошибки стали более структурированными
  • добавлены стабильные ключи путей (path)
  • улучшена вложенная агрегация ошибок
try {
  await schema.validate(data, { abortEarly: false });
} catch (err) {
  console.log(err.inner);
}

Особенности:

  • abortEarly: false теперь является более важным при сложных формах
  • структура inner всегда содержит полный список ошибок
  • порядок ошибок соответствует порядку обхода схемы

Изменения в методах isValid и validateSync

Поведение синхронной и асинхронной валидации стало более согласованным.

schema.isValid(data).then(valid => {});
schema.validateSync(data);

В 1.x:

  • синхронные методы строже проверяют типы
  • асинхронные методы стали основным рекомендуемым способом
  • расхождения между sync/async поведением минимизированы

Изменения в TypeScript-интеграции

Поддержка TypeScript стала более глубокой:

  • улучшена инференция типов из схем
  • InferType стал точнее отражать итоговую структуру
  • уменьшено количество случаев any в сложных объектах
import * as Yup from "yup";

const schema = Yup.object({
  name: Yup.string().required(),
  age: Yup.number().required()
});

type User = Yup.InferType<typeof schema>;

Особенности:

  • строгая типизация зависит от корректного использования required()
  • nullable() влияет на итоговый union-тип
  • вложенные объекты теперь корректно выводятся автоматически

Изменения в кастомных тестах (test)

Метод test получил более предсказуемую модель выполнения:

Yup.string().test(
  "custom-check",
  "Ошибка проверки",
  (value) => value?.startsWith("A")
);

В 1.x:

  • контекст this стал менее рекомендованным
  • предпочтение отдано функциональному стилю
  • улучшена работа с асинхронными тестами
Yup.string().test(
  "async-check",
  async (value) => {
    return await checkFromServer(value);
  }
);

Изменения в when (условная логика)

when() стал более строгим и явным в зависимости от зависимостей.

Yup.string().when("isActive", {
  is: true,
  then: (schema) => schema.required(),
  otherwise: (schema) => schema.notRequired()
});

Особенности 1.x:

  • зависимости должны быть явно определены
  • поведение вычисляется детерминированно
  • вложенные when стали менее “магическими” и более читаемыми

Изменения совместимости и миграционные нюансы

При переходе с 0.x на 1.x наиболее критичны следующие моменты:

  • неявные преобразования типов могут перестать работать
  • поведение undefined и null требует явного определения
  • вложенные схемы требуют более строгой структуры
  • ошибки валидации теперь всегда структурированы
  • TypeScript-типизация становится более строгой и может выявить скрытые проблемы

Особое внимание требуется уделить:

  • формам с динамическими полями
  • API-валидации с нестрогими входными данными
  • старым схемам, полагающимся на “мягкое” приведение типов