В библиотеке Superstruct ключевая идея построения схем валидации основана на композиции: более сложные структуры собираются из простых, а не описываются монолитно. Это снижает дублирование, упрощает сопровождение и делает схемы более предсказуемыми.
Композиция особенно важна в проектах, где данные имеют несколько
пересекающихся слоёв: пользовательские сущности, системные метаданные,
конфигурации и расширенные профили. Для этих задач используются
механизмы assign и extend.
assign используется для объединения нескольких структур
в одну, где итоговая схема требует выполнения всех правил
одновременно.
assign формирует новую структуру, которая:
import { object, string, number, assign } from 'superstruct';
const UserBase = object({
id: number(),
name: string(),
});
const UserMeta = object({
role: string(),
});
const User = assign(UserBase, UserMeta);
В этом случае итоговая структура User требует
наличие:
id (число)name (строка)role (строка)Если в объединяемых структурах встречаются одинаковые поля, поведение зависит от типа структур:
assign полезен, когда необходимо гарантировать
целостность данных без возможности частичного соответствия.
Типичные сценарии:
extend используется для создания новой структуры на
основе существующей с добавлением или переопределением полей.
В отличие от assign, он ориентирован на развитие базовой
модели, а не на жесткое объединение.
extend:
import { object, string, number, extend } from 'superstruct';
const BaseUser = object({
id: number(),
name: string(),
});
const ExtendedUser = extend(BaseUser, {
email: string(),
});
Результирующая структура требует:
idnameemailОдной из ключевых возможностей является изменение поведения уже существующих полей.
const Base = object({
id: number(),
name: string(),
});
const Modified = extend(Base, {
name: string(),
});
Хотя в примере тип совпадает, механизм позволяет заменять более сложные правила:
extend часто применяется при развитии доменной модели,
когда базовая сущность постепенно обрастает новыми свойствами.
Типичные случаи:
assign — строгая композиция нескольких независимых
структур;extend — развитие одной базовой структуры.assign требует полного соответствия всем входным
схемам;extend наследует основу и добавляет изменения поверх
неё.// assign: объединение равноправных структур
const A = assign(User, Meta);
// extend: развитие одной базовой структуры
const B = extend(User, {
meta: Meta,
});
Обе операции часто используются совместно с объектами, содержащими вложенные структуры.
const Address = object({
city: string(),
zip: string(),
});
const User = object({
id: number(),
name: string(),
address: Address,
});
Расширение:
const ExtendedUser = extend(User, {
role: string(),
});
Объединение:
const FullUser = assign(User, object({
role: string(),
}));
В реальных приложениях механизмы композиции структур применяются для построения слоёв данных:
assign чаще фиксирует контракт между независимыми
частями системы. extend чаще поддерживает эволюцию одной
сущности без нарушения существующей логики.
Одним из ключевых преимуществ подхода является возможность переиспользования базовых блоков.
const Timestamped = object({
createdAt: string(),
updatedAt: string(),
});
const User = extend(
object({
id: number(),
name: string(),
}),
Timestamped
);
Такой подход позволяет:
В экосистеме Superstruct assign и extend
обычно используются вместе с:
object для описания структур;string, number, boolean для
базовых типов;Комбинация этих инструментов позволяет строить многоуровневые схемы, где базовые типы остаются простыми, а сложность переносится на уровень композиции.
При использовании assign и extend валидация
происходит рекурсивно:
Ошибки валидации агрегируются, что позволяет получать полное описание несоответствий данных.