Определение формы объекта через shape

Валидация объектов в Yup строится на декларативном описании структуры данных, где каждое поле получает собственные правила проверки. Для этого используется метод object(), внутри которого формируется схема с помощью shape(). Именно shape определяет «форму» объекта — набор ключей, их типы и ограничения.

В основе подхода лежит идея строгого соответствия структуры данных заранее заданному контракту. Это особенно важно при работе с формами, API-ответами и конфигурационными объектами, где любая несогласованность приводит к ошибкам выполнения или некорректной обработке данных.

Метод object() создаёт валидатор для объектов, а shape() задаёт структуру полей внутри него. Каждый ключ в shape соответствует полю объекта, а значение — схеме валидации этого поля.

import * as Yup from 'yup';

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

В этом примере объект должен содержать три поля: name, age и email. Каждое поле проверяется независимо, но в рамках единой структуры.

Ключевой принцип: shape не просто перечисляет поля, а фиксирует контракт объекта, который должен быть соблюдён целиком.

Структура объекта как контракт данных

Использование shape позволяет рассматривать объект как строго типизированную структуру. Даже в динамическом JavaScript появляется поведение, близкое к статической типизации: отсутствие поля, лишние ключи или несоответствие типов могут быть выявлены заранее.

const userSchema = Yup.object().shape({
  id: Yup.number().required(),
  username: Yup.string().min(3).max(30),
  isActive: Yup.boolean()
});

В данном случае объект считается валидным только при соблюдении всех условий:

  • id обязательно должен быть числом
  • username ограничен длиной
  • isActive должен быть булевым значением

Любое отклонение нарушает форму объекта.

Вложенные структуры и рекурсивный shape

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

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

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

Особенность: каждая вложенная схема полностью независима, но участвует в общей проверке объекта.

Частичная валидация и гибкость формы

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

const schema = Yup.object().shape({
  title: Yup.string().required()
});

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

Для более строгого контроля используется метод strict() и конфигурации, ограничивающие лишние поля.

Работа с необязательными полями

По умолчанию поля в shape считаются необязательными, если явно не указано required(). Это позволяет описывать гибкие структуры, где часть данных может отсутствовать.

const schema = Yup.object().shape({
  phone: Yup.string(),
  address: Yup.string().required()
});

В этом случае объект может быть валидным даже без phone, но отсутствие address приведёт к ошибке.

Комбинация shape с преобразованием данных

Shape используется не только для проверки, но и для приведения данных к нужному виду через transform().

const schema = Yup.object().shape({
  price: Yup.number()
    .transform((value, originalValue) => {
      return typeof originalValue === 'string'
        ? parseFloat(originalValue)
        : value;
    })
});

Здесь shape становится частью механизма нормализации входных данных перед их валидацией.

Условная валидация внутри shape

Одной из мощных возможностей является зависимость полей друг от друга. shape позволяет комбинировать схему с when() для построения условной логики.

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

Форма объекта динамически изменяется в зависимости от значений внутри него, но структура shape остаётся центральным описанием.

Динамическое формирование структуры

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

const fields = {
  firstName: Yup.string(),
  lastName: Yup.string(),
  age: Yup.number()
};

const schema = Yup.object().shape(fields);

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

Наследование и расширение shape

Схемы можно расширять, создавая новые варианты объектов на основе существующих.

const baseSchema = Yup.object().shape({
  id: Yup.number().required()
});

const extendedSchema = baseSchema.shape({
  name: Yup.string().required()
});

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

Ограничение структуры и строгая форма объекта

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

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

В этом случае объект обязан строго соответствовать описанной структуре shape, без лишних свойств.

Поведение ошибок в shape

Каждое поле внутри shape генерирует собственное сообщение об ошибке. Ошибки агрегируются в структурированном виде, повторяя структуру объекта.

{
  name: "Name is required",
  age: "Must be a number"
}

Это позволяет легко интегрировать результат в формы и UI-компоненты, отображая ошибки рядом с соответствующими полями.

Композиция сложных схем через shape

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

const address = {
  city: Yup.string(),
  street: Yup.string()
};

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

Такой подход снижает дублирование и упрощает поддержку сложных моделей данных.

Типизация структуры и предсказуемость данных

Shape формирует предсказуемую структуру данных, что особенно важно при интеграции с внешними API. Любое несоответствие между ожидаемой и фактической формой объекта фиксируется на этапе валидации, а не во время выполнения логики приложения.

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

Масштабирование схем через shape

При росте приложения shape становится центральным механизмом управления структурой данных. Он позволяет:

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

Каждая часть shape остаётся независимой, но участвует в общей модели объекта, формируя единый контракт данных.