Определение структуры объекта

В Superstruct структура объекта задаётся через комбинацию базовых валидаторов и функции object, которая описывает форму данных в виде набора полей и их типов. Такой подход позволяет явно фиксировать контракт данных и проверять его на этапе выполнения.

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


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

Функция object принимает описание структуры и возвращает валидатор, который проверяет соответствие входного значения заданной схеме.

import { object, string, number } from 'superstruct'

const User = object({
  name: string(),
  age: number(),
})

В данном случае структура объекта строго фиксирует наличие двух полей:

  • name — строка
  • age — число

Любое отклонение от этой формы приведёт к ошибке валидации.


Принцип сопоставления ключей и структур

Каждое свойство объекта описывается отдельной структурой. Superstruct не делает неявных преобразований типов и требует явного соответствия.

const Post = object({
  title: string(),
  views: number(),
})

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

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

Вложенные структуры

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

const Address = object({
  city: string(),
  zip: number(),
})

const User = object({
  name: string(),
  address: Address,
})

Здесь структура User включает вложенный объект address, который валидируется по собственной схеме.

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


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

Для управления обязательностью используется валидатор optional.

import { object, string, optional } from 'superstruct'

const Profile = object({
  username: string(),
  bio: optional(string()),
})

Поле bio может отсутствовать либо содержать строку. При этом отсутствие поля не считается ошибкой.


Частичная структура объекта

Для работы с частичными данными применяется partial, который делает все поля объекта необязательными.

import { object, string, number, partial } from 'superstruct'

const BaseUser = object({
  name: string(),
  age: number(),
})

const PartialUser = partial(BaseUser)

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


Выбор и исключение полей

Superstruct предоставляет механизмы для формирования производных структур:

Pick — выбор конкретных полей

import { object, string, pick } from 'superstruct'

const User = object({
  name: string(),
  age: string(),
  email: string(),
})

const PublicUser = pick(User, {
  name: true,
  email: true,
})

Omit — исключение полей

import { omit } from 'superstruct'

const SafeUser = omit(User, {
  email: true,
})

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


Контроль дополнительных полей

По умолчанию Superstruct не строго запрещает наличие дополнительных ключей, однако поведение может регулироваться через дополнительные настройки и пользовательские проверки.

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


Композиция структур

Структуры можно комбинировать, формируя сложные схемы из простых блоков.

const Contact = object({
  email: string(),
  phone: string(),
})

const Employee = object({
  name: string(),
  contact: Contact,
})

Такой подход снижает дублирование и позволяет централизовать описание повторяющихся сущностей.


Использование refine для объектов

Для более сложной логики валидации применяется refine, позволяющий накладывать дополнительные ограничения на уже описанную структуру.

import { object, string, refine } from 'superstruct'

const Password = refine(string(), 'Password', (value) => {
  return value.length >= 8
})

При применении к объектам это позволяет проверять зависимости между полями.


Доступ к типизации объекта

Superstruct интегрируется с TypeScript через вывод типов на основе схемы.

import { Infer, object, string, number } from 'superstruct'

const User = object({
  name: string(),
  age: number(),
})

type UserType = Infer<typeof User>

UserType автоматически соответствует описанной структуре и синхронизируется с валидатором.


Переиспользование структур

Структуры объектов в Superstruct проектируются как независимые единицы, которые можно:

  • комбинировать
  • расширять
  • переопределять через композицию
  • использовать в других структурах
const Base = object({
  id: number(),
})

const Extended = object({
  ...Base.schema,
  name: string(),
})

Хотя прямое распространение схемы через spread используется реже, концептуально это отражает идею расширяемости.


Моделирование доменных сущностей

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

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

Каждая структура выступает формальным описанием допустимого состояния данных.


Составные структуры и масштабирование

При увеличении сложности системы структура объекта становится композиционной единицей архитектуры данных. Разделение схем на независимые блоки позволяет:

  • уменьшить связанность
  • упростить тестирование
  • повторно использовать валидаторы
  • централизовать бизнес-логику валидации

Принцип явного контракта данных

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