Literal

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

Литеральная структура в Superstruct описывает правило: значение должно совпадать с эталоном строго и без отклонений. Проверка выполняется через строгое сравнение (===) для примитивов и ссылочное сравнение для объектов.

Это означает:

  • строки должны совпадать полностью;
  • числа должны быть идентичны;
  • булевы значения допускают только true или false в зависимости от конфигурации;
  • объекты и массивы должны ссылаться на тот же экземпляр.

Любое отклонение приводит к ошибке валидации.

Создание литеральной структуры

В Superstruct литеральные значения создаются с помощью функции literal.

import { literal } from 'superstruct';

const ActiveStatus = literal('active');

Такое определение фиксирует допустимое значение строго как строку 'active'. Любые другие строки будут считаться невалидными.

Пример проверки:

ActiveStatus.assert('active'); // проходит
ActiveStatus.assert('inactive'); // ошибка

Примитивные литералы

Чаще всего литералы применяются к строкам, числам и булевым значениям.

Строки

const Role = literal('admin');

Значение строго фиксировано:

Role.assert('admin'); // ok
Role.assert('user');   // error

Числа

const HttpOk = literal(200);
HttpOk.assert(200); // ok
HttpOk.assert(404); // error

Булевы значения

const IsEnabled = literal(true);
IsEnabled.assert(true);  // ok
IsEnabled.assert(false); // error

Литеральные объекты и ссылки

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

const config = { mode: 'dark' };

const Theme = literal(config);

Корректным будет только тот же самый объект:

Theme.assert(config); // ok
Theme.assert({ mode: 'dark' }); // error

Даже идентичная по структуре копия считается отличной, поскольку это другой объект в памяти.

Составные структуры и объединения

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

import { union, literal } from 'superstruct';

const Direction = union([
  literal('left'),
  literal('right'),
  literal('up'),
  literal('down')
]);

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

Проверка:

Direction.assert('left');  // ok
Direction.assert('down');  // ok
Direction.assert('forward'); // error

Альтернатива enum-подходу

Литеральные объединения часто используются вместо перечислений. В отличие от TypeScript enum, здесь нет дополнительного рантайм-слоя, а поведение полностью определяется структурой.

Преимущества подхода:

  • явная проверка значений;
  • отсутствие скрытых преобразований;
  • гибкость композиции через union.

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

Выведение типов в TypeScript

Superstruct интегрируется с TypeScript, и литеральные структуры позволяют точно выводить типы.

import { Infer, literal } from 'superstruct';

const Status = literal('success');

type StatusType = Infer<typeof Status>;

StatusType будет строго ограничен значением 'success', что позволяет TypeScript на уровне типов синхронизироваться с runtime-валидацией.

При объединениях вывод становится расширенным:

const Result = union([
  literal('success'),
  literal('error')
]);

type ResultType = Infer<typeof Result>;

В результате тип будет 'success' | 'error'.

Поведение ошибок

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

Типичная ошибка содержит:

  • путь к значению (если оно вложено);
  • ожидаемое значение;
  • фактическое значение.

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

Использование в сложных структурах

Литеральные значения часто встречаются внутри объектов и вложенных структур.

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

const UserEvent = object({
  type: literal('user.created'),
  payload: object({
    id: string(),
  })
});

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

Особенности сравнения и ограничения

Литеральные структуры имеют ряд особенностей:

  • NaN не считается равным самому себе, поэтому его использование требует осторожности;
  • объекты сравниваются по ссылке, а не по содержимому;
  • массивы также требуют идентичной ссылки;
  • преобразование типов (например, строка → число) не выполняется автоматически.

Роль в архитектуре валидации

Литеральные значения выполняют роль жёстких ограничителей доменной модели. Они позволяют:

  • фиксировать управляющие состояния;
  • задавать типы событий;
  • определять допустимые режимы работы системы;
  • создавать псевдо-перечисления без дополнительных конструкций.

В комбинации с union, object и `enums-подобными паттернами они формируют основу строгих схем в Superstruct, обеспечивая предсказуемость данных на уровне исполнения.