В системах валидации данных ключевым инструментом становится переиспользование уже определённых схем. Вместо создания новых структур с нуля используется трансформация существующих описаний. Подход, основанный на композиции, позволяет строить сложные модели данных без дублирования логики.
В Superstruct подобная функциональность реализована через утилиты pick и omit, которые позволяют создавать производные структуры на основе уже существующих определений.
Основной принцип:
Эти операции работают аналогично утилитам TypeScript
Pick и Omit, но применяются к
runtime-схемам.
pick создаёт новую структуру, содержащую только явно
перечисленные поля исходной схемы. Остальные поля игнорируются на уровне
валидации.
const NewStruct = pick(OriginalStruct, ['fieldA', 'fieldB'])
Результат — структура, в которой валидируются только указанные ключи.
import { object, string, number } from 'superstruct'
const User = object({
id: number(),
name: string(),
email: string(),
password: string(),
})
Исходная структура содержит четыре поля, но в реальных сценариях часто требуется использовать только часть данных.
import { pick } from 'superstruct'
const PublicUser = pick(User, ['id', 'name'])
Теперь PublicUser валидирует только:
Остальные поля полностью исключены из проверки.
При использовании pick:
pick используется для создания ограниченных
представлений данных:
omit создаёт новую структуру, исключая указанные поля из
исходной схемы. Остальные поля сохраняются без изменений.
const NewStruct = omit(OriginalStruct, ['fieldA', 'fieldB'])
import { omit } from 'superstruct'
const SafeUser = omit(User, ['password'])
В результате структура SafeUser содержит:
Поле password полностью исключено из схемы.
В отличие от ручного пересоздания схемы:
const SafeUser = object({
id: number(),
name: string(),
email: string(),
})
omit позволяет:
Если базовая структура изменяется:
const User = object({
id: number(),
name: string(),
email: string(),
password: string(),
role: string(),
})
то omit(User, ['password']) автоматически включает новое
поле role без необходимости модификации производной
схемы.
| Операция | Поведение | Когда используется |
|---|---|---|
| pick | включает только указанные поля | публичные ответы, ограниченные модели |
| omit | исключает указанные поля | фильтрация чувствительных данных |
В сложных схемах часто требуется последовательное применение трансформаций.
const Base = object({
id: number(),
name: string(),
email: string(),
password: string(),
role: string(),
})
const Intermediate = omit(Base, ['password'])
const Public = pick(Intermediate, ['id', 'name'])
Результат:
id и namepassword гарантировано на раннем этапеpick и omit работают на уровне ключей
объекта и не выполняют глубокую трансформацию вложенных объектов
автоматически.
const Profile = object({
user: User,
settings: object({
theme: string(),
notifications: boolean(),
}),
})
const PublicProfile = omit(Profile, ['user'])
Исключается только верхнеуровневый ключ user, вложенные
структуры сохраняются без изменений.
Глубокая модификация требует явного определения:
const PublicUser = pick(User, ['id', 'name'])
const PublicProfile = object({
user: PublicUser,
settings: Profile.schema.settings,
})
const CreateUser = pick(User, ['name', 'email', 'password'])
const UserResponse = omit(User, ['password'])
const AdminUserView = User
или с ограничениями:
const AdminUserView = omit(User, [])
const LoginForm = pick(User, ['email', 'password'])
Ручное создание новой структуры приводит к рассинхронизации:
// менее надёжно
const SafeUser = object({
id: number(),
name: string(),
})
pick(Profile, ['user.id']) // некорректный подход
Подобная запись не интерпретируется как путь.
При изменении базовой структуры производные схемы, созданные без pick/omit, требуют ручного обновления.
В контексте построения схем на базе Superstruct эти операции выполняют роль:
Они уменьшают связность между слоями приложения и повышают устойчивость к изменениям модели данных.
В масштабных системах типичная структура выглядит следующим образом:
pick и omit становятся инструментами
управления вариациями одной и той же сущности без её дублирования.
Несмотря на это, в большинстве практических сценариев покрывает основную часть задач фильтрации данных.