В Superstruct структура record предназначена для
описания объектов-словарей, где набор ключей заранее не фиксирован, но
строго контролируются типы этих ключей и значений. Это один из ключевых
инструментов для моделирования динамических коллекций данных, таких как
конфигурации, справочники, кэши и маппинги.
record описывает объект, в котором:
В отличие от object-подобных схем, где структура
фиксирована, record ориентирован на произвольное количество
однотипных полей.
Основная идея:
В Superstruct record создаётся с помощью функции:
import { record, string, number } from 'superstruct'
const Schema = record(string(), number())
Здесь:
string() описывает допустимые ключи;number() описывает значения.Пример валидного объекта:
const data = {
a: 1,
b: 2,
c: 3
}
Любой ключ является строкой, и каждое значение — числом.
Наиболее частый сценарий — использование строковых ключей:
const UserScores = record(string(), number())
Пример:
{
alice: 10,
bob: 15,
charlie: 20
}
Такой вариант эквивалентен словарю или хеш-таблице.
Хотя в JavaScript ключи объектов всегда приводятся к строке, Superstruct позволяет описывать числовые ключи:
import { record, number, string } from 'superstruct'
const NumericKeys = record(number(), string())
Пример:
{
1: "one",
2: "two",
3: "three"
}
Фактически ключи будут строками "1", "2",
но проверка будет учитывать числовую семантику.
Одной из наиболее мощных возможностей является использование
pattern или пользовательских структур для ключей.
import { record, string, pattern } from 'superstruct'
const HexMap = record(
pattern(/^[a-f0-9]{6}$/),
string()
)
Пример:
{
ff0000: "red",
00ff00: "green",
0000ff: "blue"
}
Здесь ключи обязаны быть шестнадцатеричными строками.
Для строгого контроля используется enums-подобная
структура через пользовательскую проверку:
import { record, string, enums } from 'superstruct'
const RoleMap = record(
enums(['admin', 'user', 'guest']),
string()
)
Пример:
{
admin: "Alice",
user: "Bob",
guest: "Eve"
}
Любой ключ вне списка приведёт к ошибке валидации.
record не ограничивается примитивами в значениях. Можно
использовать вложенные структуры.
import { record, object, string, number } from 'superstruct'
const UserMap = record(
string(),
object({
id: number(),
name: string()
})
)
Пример данных:
{
u1: { id: 1, name: "Alice" },
u2: { id: 2, name: "Bob" }
}
Такой подход часто используется для хранения сущностей, индексированных по идентификатору.
record может быть вложенным, формируя многомерные
словари.
const Matrix = record(
string(),
record(string(), number())
)
Пример:
{
row1: { col1: 1, col2: 2 },
row2: { col1: 3, col2: 4 }
}
Такая структура используется для:
При проверке данных Superstruct выполняет два уровня контроля:
Если хотя бы одно значение не соответствует схеме, весь объект считается невалидным.
Пример ошибки:
const Schema = record(string(), number())
const data = {
a: 1,
b: "invalid"
}
Ошибка возникает из-за значения "invalid", так как оно
не является числом.
Пустой объект всегда валиден для record, если нет
дополнительных ограничений:
{}
Это поведение важно учитывать при работе с опциональными словарями, кэшами или накопительными структурами.
import { struct, record, string, number } from 'superstruct'
const AppConfig = struct({
settings: record(string(), string()),
metrics: record(string(), number())
})
Пример:
{
settings: {
theme: "dark",
language: "ru"
},
metrics: {
clicks: 100,
views: 200
}
}
import { union, record, string, number } from 'superstruct'
const Data = union([
record(string(), number()),
record(string(), string())
])
Такой подход позволяет описывать гибкие схемы, где структура значений зависит от контекста.
const Config = record(string(), string())
Используется для хранения переменных окружения, настроек модулей, параметров приложения.
const Cache = record(string(), object({
value: string(),
timestamp: number()
}))
Позволяет хранить данные по ключу с метаинформацией.
const Users = record(string(), object({
id: number(),
email: string()
}))
Подходит для in-memory баз данных.
const Translations = record(
string(),
record(string(), string())
)
Пример:
{
en: { hello: "Hello", bye: "Goodbye" },
ru: { hello: "Привет", bye: "Пока" }
}
record работает эффективно даже с большими объектами,
поскольку:
Однако глубоко вложенные record могут увеличивать
стоимость валидации из-за рекурсивной проверки значений.
const Schema = record(string(), number())
{
a: "1" // строка вместо числа
}
const Schema = record(pattern(/^[a-z]+$/), number())
{
"123abc": 10 // не проходит регулярное выражение
}
const Schema = record(string(), number())
{
a: 1,
b: { value: 2 } // объект вместо числа
}
record часто используется вместо Map,
когда:
В отличие от Map, структура record:
Главное свойство record — способность описывать
неизвестное количество полей при строгом контроле их формы. Это делает
его универсальным инструментом для любых “словарных” структур данных,
где важна не фиксированная схема объекта, а единообразие элементов
внутри него.