Что такое Superstruct

Superstruct — библиотека для валидации и структурирования данных в JavaScript и TypeScript, ориентированная на декларативное описание схем и строгую проверку входящих значений. Основная идея заключается в том, чтобы описывать форму данных в виде композиции примитивов и структур, а затем проверять соответствие этих данных заранее определённым правилам.

В основе подхода лежит понятие структуры — функции-валидатора, которая принимает значение и проверяет его соответствие определённой форме. Если значение соответствует ожиданиям, оно возвращается как валидное; если нет — формируется ошибка.

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

Ключевая особенность — декларативность: вместо ручной проверки условий создаётся схема данных, которая описывает правила один раз и применяется повторно.

Примитивные структуры

Библиотека предоставляет набор базовых валидаторов для простых типов данных:

  • строки
  • числа
  • булевы значения
  • любые значения
  • nullable и optional модификаторы

Пример базовой проверки:

import { string, number, boolean, validate } from 'superstruct';

const schema = {
  name: string(),
  age: number(),
  isActive: boolean(),
};

validate(
  { name: 'Alex', age: 30, isActive: true },
  schema
);

Каждая структура представляет собой функцию, возвращающую валидатор с заданными правилами.

Составные структуры

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

Объекты

Структура объекта описывает набор полей и их типы:

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

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

Объект проверяется рекурсивно: каждое поле валидируется согласно своей структуре.

Массивы

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

import { array, number } from 'superstruct';

const Numbers = array(number());

Каждый элемент массива проходит отдельную проверку.

Объединения типов

Поддерживается логика альтернативных структур:

import { union, string, number } from 'superstruct';

const Value = union([string(), number()]);

Значение считается валидным, если соответствует хотя бы одному из вариантов.

Кастомные структуры

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

import { define } from 'superstruct';

const PositiveNumber = define('PositiveNumber', (value) => {
  return typeof value === 'number' && value > 0;
});

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

Валидация и обработка ошибок

Функция validate возвращает результат проверки в виде кортежа:

const [error, result] = validate(data, schema);
  • error содержит информацию о несоответствии
  • result содержит преобразованные или проверенные данные

Если требуется выброс исключения, используется assert-подобный подход:

import { assert } from 'superstruct';

assert(data, schema);

При несоответствии данных выбрасывается ошибка с подробным описанием пути до проблемного поля.

Путь ошибок и диагностика

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

  • поле объекта
  • индекс массива
  • тип несоответствия

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

Модификаторы структур

Существуют дополнительные инструменты для управления поведением проверок.

optional

Позволяет сделать поле необязательным:

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

const Schema = object({
  name: string(),
  nickname: optional(string()),
});

nullable

Разрешает значение null:

import { nullable, string } from 'superstruct';

const MaybeString = nullable(string());

Преобразование данных

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

Пример — преобразование строки в число:

import { coerce, number, string } from 'superstruct';

const NumberFromString = coerce(number(), string(), (value) =>
  parseFloat(value)
);

Такая схема полезна при обработке внешних API или пользовательского ввода.

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

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

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

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

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

Контекст и расширение логики

При необходимости валидация может учитывать внешний контекст, например зависимости между полями. Для этого используются пользовательские функции-валидаторы, где проверка выполняется на уровне всей структуры.

Пример:

import { refine, object, number } from 'superstruct';

const Range = object({
  min: number(),
  max: number(),
});

const ValidRange = refine(Range, (value) => {
  return value.min <= value.max;
});

Назначение и область применения

Подобные системы валидации применяются в ситуациях, где требуется строгий контроль входящих данных:

  • API-сервисы
  • обработка форм
  • валидация конфигураций
  • работа с внешними источниками данных
  • построение типов в runtime

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

Особенности архитектуры

Superstruct построена на функциональной модели без избыточной магии. Каждая структура — это чистая функция, что обеспечивает:

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

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