В Superstruct набор утилит строится вокруг единого принципа: каждая структура данных описывается как независимый валидатор, который можно комбинировать, расширять и трансформировать. Утилиты делятся на несколько категорий — функции выполнения проверок, преобразования значений и композиции структур.
create — выполняет валидацию и возвращает значение, приведённое к описанной структуре. В случае ошибки выбрасывает исключение.
import { create, string } from 'superstruct';
const Name = string();
const value = create('Alex', Name); // 'Alex'
assert — аналогична create, но
используется, когда требуется явная проверка с выбросом исключения без
возврата значения.
import { assert, number } from 'superstruct';
assert(42, number()); // проходит
assert('42', number()); // ошибка
is — возвращает булево значение, определяющее соответствие структуры.
import { is, boolean } from 'superstruct';
is(true, boolean()); // true
is(1, boolean()); // false
validate — предоставляет расширенный результат проверки: валидность и преобразованное значение или ошибку.
import { validate, string } from 'superstruct';
const [error, value] = validate(123, string());
mask — приводит объект к структуре, заполняя
недостающие поля undefined или значениями по умолчанию,
если это возможно.
import { mask, object, string, number } from 'superstruct';
const User = object({
name: string(),
age: number()
});
mask({ name: 'Alex' }, User);
// { name: 'Alex', age: undefined }
Superstruct предоставляет утилиту Infer, позволяющую извлекать TypeScript-тип из структуры.
import { Infer, string } from 'superstruct';
const Name = string();
type NameType = Infer<typeof Name>;
Это обеспечивает синхронизацию между runtime-валидацией и статической типизацией.
Позволяет сделать поле необязательным. Если значение отсутствует, оно считается валидным.
import { optional, string, object } from 'superstruct';
const User = object({
nickname: optional(string())
});
Разрешает значение null как допустимое.
import { nullable, number } from 'superstruct';
const Age = nullable(number());
Добавляет значение по умолчанию, если входные данные не содержат поле.
import { defaulted, string } from 'superstruct';
const Name = defaulted(string(), 'Anonymous');
Важная особенность: значение по умолчанию применяется только при
undefined, но не при null.
Позволяет преобразовать входные данные перед валидацией. Используется для нормализации типов.
import { coerce, number, string } from 'superstruct';
const Age = coerce(number(), string(), (value) => Number(value));
Такой подход позволяет безопасно обрабатывать данные из внешних источников.
Добавляет пользовательскую проверку поверх базовой структуры.
import { refine, number } from 'superstruct';
const Positive = refine(number(), 'Positive', (value) => {
return value > 0;
});
Refine не изменяет тип, а только накладывает дополнительное ограничение.
Позволяет создавать собственные структуры с произвольной логикой проверки.
import { define } from 'superstruct';
const EvenNumber = define('EvenNumber', (value) => {
return typeof value === 'number' && value % 2 === 0;
});
Создаёт структурированный объект с заданной схемой полей.
import { object, string, number } from 'superstruct';
const User = object({
name: string(),
age: number()
});
Описывает массив элементов одного типа.
import { array, number } from 'superstruct';
const Numbers = array(number());
Фиксированная структура массива с разными типами по позициям.
import { tuple, string, number } from 'superstruct';
const Pair = tuple([string(), number()]);
Используется для объектов с динамическими ключами, где все значения имеют одинаковую структуру.
import { record, number } from 'superstruct';
const Scores = record(string(), number());
Позволяет объединять несколько структур, где валидным считается любое совпадение.
import { union, string, number } from 'superstruct';
const StringOrNumber = union([string(), number()]);
Требует соответствия сразу нескольким структурам.
import { intersection, object, string } from 'superstruct';
const A = object({ name: string() });
const B = object({ surname: string() });
const Full = intersection([A, B]);
Фиксированное значение.
import { literal } from 'superstruct';
const Yes = literal('yes');
Ограничение значений набором допустимых вариантов.
import { enums } from 'superstruct';
const Role = enums(['admin', 'user', 'guest']);
Ограничивает длину строк или массивов.
import { size, string } from 'superstruct';
const Code = size(string(), 5, 10);
Проверка строки по регулярному выражению.
import { pattern, string } from 'superstruct';
const Email = pattern(string(), /^[^\s@]+@[^\s@]+\.[^\s@]+$/);
Удаляет пробелы и проверяет уже очищенное значение.
import { trimmed, string } from 'superstruct';
const Name = trimmed(string());
Утилиты Superstruct не являются изолированными. Они проектировались как слои, накладываемые друг на друга. Порядок применения влияет на результат валидации и трансформации.
Пример комбинированной структуры:
import { object, string, defaulted, trimmed, size } from 'superstruct';
const User = object({
name: size(trimmed(string()), 2, 30),
nickname: defaulted(string(), 'guest')
});
Здесь данные проходят цепочку:
trimmed)size)defaulted)object)Superstruct обеспечивает тесную связь между описанием структуры и
TypeScript-типами. Утилита Infer позволяет автоматически
синхронизировать типы.
import { object, string, number, Infer } from 'superstruct';
const User = object({
name: string(),
age: number()
});
type UserType = Infer<typeof User>;
Получаемый тип полностью повторяет структуру валидатора, исключая необходимость ручного дублирования интерфейсов.
При сложных композициях важно учитывать:
coerce выполняется до основной валидацииdefaulted срабатывает при отсутствии значенияrefine применяется после базовой проверкиmask не выбрасывает ошибки, а нормализует
структуруПример последовательной обработки:
import { coerce, defaulted, refine, number } from 'superstruct';
const Age = refine(
defaulted(
coerce(number(), string(), Number),
18
),
'Age',
(v) => v >= 0
);
При использовании утилит важно учитывать, что каждая структура является функцией проверки, а не просто описанием данных. Это означает:
Такой подход позволяет строить декларативные схемы, которые остаются предсказуемыми даже при сложной логике обработки данных