Array

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

Основной строительный блок для работы с массивами в Superstruct — функция, описывающая структуру элемента:

import { array, string } from 'superstruct'

const StringArray = array(string)

В этом примере создаётся структура, которая принимает только массив строк. Любой элемент массива проверяется отдельно, и при несоответствии типу валидация завершится ошибкой.

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

Проверка элементов массива

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

import { array, number } from 'superstruct'

const NumberArray = array(number)

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

Пример допустимых и недопустимых значений:

  • допустимо: [1, 2, 3]
  • недопустимо: [1, "2", 3]

В последнем случае строка "2" приводит к ошибке валидации.

Вложенные массивы

Superstruct поддерживает произвольную глубину вложенности:

import { array, number } from 'superstruct'

const Matrix = array(array(number))

Такая структура описывает двумерный массив чисел.

Пример корректного значения:

[
  [1, 2],
  [3, 4]
]

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

Ограничение длины массива

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

Минимальная длина

import { array, string, min } from 'superstruct'

const NonEmptyStringArray = min(array(string), 1)

Такая структура запрещает пустые массивы.

Максимальная длина

import { array, number, max } from 'superstruct'

const LimitedArray = max(array(number), 5)

В этом случае массив не может содержать более пяти элементов.

Диапазон длины

Комбинирование ограничений позволяет задавать диапазоны:

import { array, size, string } from 'superstruct'

const FixedRangeArray = size(array(string), 2, 4)

Здесь допустимы массивы длиной от 2 до 4 элементов включительно.

Проверка уникальности и пользовательские правила

Помимо встроенных ограничений, Superstruct позволяет добавлять собственные правила через refine.

Пример проверки уникальности элементов:

import { array, number, refine } from 'superstruct'

const UniqueArray = refine(array(number), 'UniqueArray', (value) => {
  return new Set(value).size === value.length
})

Такая структура гарантирует отсутствие дубликатов.

Коэрция и преобразование входных данных

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

import { array, string, coerce } from 'superstruct'

const StringArray = coerce(array(string), array(string), (value) => {
  return value.map(String)
})

В этом примере все элементы приводятся к строкам перед валидацией.

Также возможно преобразование не-массивных значений в массив:

const EnsureArray = coerce(array(string), (value) => {
  return Array.isArray(value) ? value : [value]
})

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

Объединение массивов с другими структурами

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

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

const UserList = array(
  object({
    id: number(),
    name: string()
  })
)

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

Опциональные и допускающие null элементы

Внутри массива можно использовать модификаторы optional и nullable:

import { array, string, nullable } from 'superstruct'

const ArrayWithNullable = array(nullable(string))

Такая структура допускает значения string или null внутри массива.

Поведение при ошибках валидации

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

const data = ["ok", 123, "ok"]

Для структуры array(string) ошибка будет указывать на индекс 1, где находится число вместо строки.

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

Композиция массивов с union

Массивы могут содержать элементы разных типов через union:

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

const MixedArray = array(union([string, number]))

Такая структура допускает массив, состоящий из строк и чисел одновременно.

Производительность и ленивые проверки

Проверка массива выполняется последовательно по элементам. При большом объёме данных ошибка прекращает дальнейшую проверку, как только обнаружено первое несоответствие.

Это снижает вычислительную нагрузку при обработке больших коллекций, особенно в серверных приложениях.

Типизация и интеграция с TypeScript

Superstruct предоставляет автоматическое выведение типов:

import { Infer, array, string } from 'superstruct'

const StringArray = array(string)

type StringArrayType = Infer<typeof StringArray>

В результате тип StringArrayType становится эквивалентным string[], что обеспечивает согласованность между рантайм-валидацией и системой типов.

Использование в реальных сценариях данных

Массивы в Superstruct часто применяются при работе с:

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

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

Поведение при частично валидных данных

При обработке частично корректных массивов возможны стратегии:

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

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

Глубокая вложенность и рекурсивные структуры

Массивы могут использоваться для описания рекурсивных структур, например деревьев:

import { array, object, string, lazy } from 'superstruct'

const Node = lazy(() =>
  object({
    value: string(),
    children: array(Node)
  })
)

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