Объекты

Объектная модель данных в Yup строится вокруг схемы object(), которая описывает структуру, вложенность и правила валидации для сложных сущностей. При использовании YupResolver в связке с формами (например, React Hook Form) именно объектные схемы становятся центральным элементом описания формы, так как позволяют декларативно задавать правила проверки для каждого поля и уровня вложенности.

Базовое определение объекта

Схема объекта в Yup создаётся через Yup.object() и принимает в качестве аргумента описание полей через shape.

import * as Yup from "yup";

const schema = Yup.object({
  name: Yup.string().required("Имя обязательно"),
  age: Yup.number().required("Возраст обязателен").min(0),
});

Конструкция shape может быть использована явно:

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

Обе формы эквивалентны, но shape чаще используется для повышения читаемости в сложных схемах.

Принцип валидации объектов

Yup выполняет валидацию по ключам объекта. Каждый ключ сопоставляется с отдельной схемой, а итоговый результат агрегируется в единый объект ошибок.

При использовании YupResolver этот процесс становится промежуточным слоем между формой и схемой:

  • форма передаёт значения объекта
  • Yup выполняет валидацию каждого поля
  • YupResolver преобразует ошибки в формат, совместимый с системой управления формами

Обязательные и необязательные поля

По умолчанию поля в объекте считаются необязательными, если явно не указано обратное.

const schema = Yup.object({
  email: Yup.string().required("Email обязателен"),
  phone: Yup.string(), // необязательное поле
});

Важно учитывать, что отсутствие required() означает допустимость undefined, но не всегда null. Поведение можно уточнять через дополнительные методы:

Yup.string().nullable().required()

Вложенные объекты

Одно из ключевых преимуществ Yup — поддержка глубоко вложенных структур.

const schema = Yup.object({
  user: Yup.object({
    name: Yup.string().required(),
    address: Yup.object({
      city: Yup.string().required(),
      zip: Yup.string().required(),
    }),
  }),
});

В контексте YupResolver такие структуры автоматически преобразуются в плоские ошибки с использованием точечной нотации:

  • user.name
  • user.address.city

Это позволяет напрямую связывать ошибки с полями формы.

Поведение с отсутствующими объектами

Если вложенный объект не передан, Yup может вести себя по-разному в зависимости от конфигурации:

const schema = Yup.object({
  profile: Yup.object({
    bio: Yup.string(),
  }).required("Профиль обязателен"),
});

При отсутствии profile вся ветка считается невалидной.

Для более гибкого поведения используется default:

profile: Yup.object({
  bio: Yup.string(),
}).default({})

stripUnknown и очистка объектов

При работе с объектами важно контролировать лишние поля. Yup поддерживает опцию stripUnknown, которая удаляет все свойства, не описанные в схеме.

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

Поведение:

  • вход: { name: "A", age: 20 }
  • выход: { name: "A" }

В связке с YupResolver это особенно важно для защиты от «грязных» данных из формы.

Преобразование объектов

Метод transform позволяет изменять входной объект перед валидацией.

const schema = Yup.object({
  settings: Yup.object({
    theme: Yup.string(),
  }).transform((value) => value ?? { theme: "light" }),
});

Это используется для нормализации структуры данных до применения правил проверки.

Работа с массивами объектов внутри объекта

Часто объекты содержат массивы, и Yup корректно поддерживает такие структуры.

const schema = Yup.object({
  users: Yup.array().of(
    Yup.object({
      name: Yup.string().required(),
      role: Yup.string().required(),
    })
  ),
});

YupResolver в этом случае формирует ошибки вида:

  • users[0].name
  • users[1].role

Интеграция с YupResolver

YupResolver выступает адаптером между Yup и системой форм. При передаче объектной схемы он выполняет следующие шаги:

  1. Принимает объект значений формы
  2. Передаёт его в schema.validate()
  3. Обрабатывает результат или ошибки
  4. Возвращает стандартизированный объект ошибок

Пример использования:

import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";

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

const {
  register,
  handleSubmit,
  formState: { errors },
} = useForm({
  resolver: yupResolver(schema),
});

Поведение ошибок в объектных схемах

Ошибки в объектных схемах всегда структурированы. Это важно для корректного отображения UI:

errors.user?.name?.message

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

  • ошибки вложенных объектов доступны через цепочку
  • массивы используют индекс
  • корневые ошибки находятся на верхнем уровне

Типизация объектов в TypeScript

Yup позволяет извлекать типы из объектных схем:

import * as Yup from "yup";

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

type FormData = Yup.InferType<typeof schema>;

Это обеспечивает согласованность между схемой и типами данных формы.

Частичные объекты и deep partial

Для случаев редактирования данных часто требуется частичная валидация:

Yup.object({
  name: Yup.string(),
  profile: Yup.object({
    bio: Yup.string(),
  }),
}).partial();

Метод partial() делает все поля необязательными, включая вложенные объекты.

Условная валидация внутри объектов

Объекты часто содержат зависимости между полями:

const schema = Yup.object({
  isCompany: Yup.boolean(),
  companyName: Yup.string().when("isCompany", {
    is: true,
    then: (schema) => schema.required(),
  }),
});

В объектной структуре такие условия работают на любом уровне вложенности.

Распространённые проблемы при работе с объектами

При использовании YupResolver с объектами часто возникают типовые ошибки:

  • несоответствие структуры defaultValues и схемы
  • отсутствие вложенных объектов в initial state
  • попытка валидировать undefined вместо {}

Корректная инициализация предотвращает большинство проблем:

const defaultValues = {
  user: {
    name: "",
  },
};

Поведение null и undefined в объектах

Yup различает null и undefined:

  • undefined — отсутствие значения
  • null — явное пустое значение

Контроль осуществляется через:

Yup.object().nullable().default(null)

Глубокая валидация и производительность

При сложных объектах с глубокой вложенностью важно учитывать:

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

Оптимизация достигается через:

  • упрощение структуры
  • использование when вместо дублирующих схем
  • минимизацию лишних вложенных объектов