Size для массивов и строк

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

size позволяет ограничивать:

  • минимальную длину;
  • максимальную длину;
  • точный размер;
  • диапазон размеров.

Функция особенно полезна при валидации:

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

Сигнатура функции size

size(struct, min, max?)

Параметры

Параметр Описание
struct Базовая структура
min Минимальный размер
max Максимальный размер

Если указан только min, значение считается точным размером.


Импорт

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

Проверка длины строки

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

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

const Username = size(string(), 3, 20)

assert('alex', Username)

Ошибка

assert('ab', Username)

Результат:

Expected a string with a length between `3` and `20` but received one with a length of `2`

Точная длина строки

Если передан только один числовой аргумент, size проверяет точное совпадение.

const HexColor = size(string(), 7)

assert('#FFAA00', HexColor)

Неверное значение

assert('#FFF', HexColor)

Ограничение максимальной длины

const ShortText = size(string(), 0, 100)

Здесь:

  • минимум — 0;
  • максимум — 100.

Проверка размеров массивов

Ограничение количества элементов

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

const Scores = size(array(number()), 1, 5)

Допустимые значения:

[10]
[10, 20]
[10, 20, 30, 40, 50]

Недопустимые:

[]
[1, 2, 3, 4, 5, 6]

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

const RGB = size(array(number()), 3)

Подходящие данные:

[255, 120, 0]

Ошибка:

[255, 120]

Работа с вложенными структурами

size можно комбинировать с object.

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

const Article = object({
  title: size(string(), 5, 100),
  tags: size(array(string()), 1, 10)
})

Проверяемые ограничения

Поле Ограничение
title от 5 до 100 символов
tags от 1 до 10 тегов

Проверка пустых строк

Запрет пустого значения

const RequiredString = size(string(), 1)

Допустимо:

'hello'

Недопустимо:

''

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


Комбинирование с refine

size можно объединять с дополнительными правилами.

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

const Password = refine(
  size(string(), 8, 32),
  'Password',
  value => {
    return /[A-Z]/.test(value)
  }
)

Проверяются:

  • длина от 8 до 32 символов;
  • наличие заглавной буквы.

Валидация массивов объектов

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

const User = object({
  name: string()
})

const Users = size(array(User), 1, 100)

Использование с optional

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

const Nickname = optional(
  size(string(), 3, 20)
)

Допустимо:

undefined
'player'

Ошибка:

'ab'

Валидация Set и Map

size работает не только со строками и массивами.

Set

import {
  set,
  number,
  size
} from 'superstruct'

const UniqueIds = size(set(number()), 1, 10)

Map

import {
  map,
  string,
  number,
  size
} from 'superstruct'

const Statistics = size(
  map(string(), number()),
  1,
  20
)

Использование вместе с union

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

const Payload = union([
  size(string(), 1, 50),
  size(array(string()), 1, 5)
])

Допустимые значения:

'hello'
['a', 'b']

Валидация параметров API

Ограничение массива идентификаторов

const Ids = size(array(string()), 1, 100)

Типичный сценарий:

{
  "ids": ["1", "2", "3"]
}

Проверка длины комментария

const Comment = size(string(), 1, 500)

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

assert

Выбрасывает исключение.

assert([], size(array(string()), 1))

is

Возвращает boolean.

import { is } from 'superstruct'

is([1, 2], size(array(number()), 1, 5))

validate

Возвращает массив с ошибкой.

import { validate } from 'superstruct'

const [error, value] = validate(
  [],
  size(array(string()), 1)
)

Отличие size от min и max

В Superstruct существуют и отдельные проверки:

  • min
  • max

Однако size удобнее для диапазонов.

Пример

size(string(), 5, 20)

Вместо:

refine(
  refine(string(), 'min', v => v.length >= 5),
  'max',
  v => v.length <= 20
)

Практические сценарии

Проверка списка ролей

const Roles = size(array(string()), 1, 3)

Ограничение количества файлов

const Files = size(array(string()), 1, 10)

Проверка PIN-кода

const PinCode = size(string(), 4)

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

const Point3D = size(array(number()), 3)

Частые ошибки

Использование size для числа

Неправильно:

size(number(), 1, 10)

size не проверяет числовой диапазон значения.

Правильно:

min(number(), 1)
max(number(), 10)

Путаница между длиной и содержимым

size(array(string()), 3)

Проверяется только количество элементов, а не содержимое строк.


Проверка сложных структур

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

const Product = object({
  title: size(string(), 3, 100),
  images: size(array(string()), 1, 8),
  tags: size(array(string()), 0, 20)
})

const Catalog = size(array(Product), 1, 500)

Влияние на производительность

size выполняет простую проверку свойства:

  • length
  • size

Поэтому операция выполняется очень быстро даже на больших массивах.

Основные затраты обычно связаны не с size, а с глубокой валидацией вложенных структур.


Лучшие практики

Использование констант

const MIN_PASSWORD = 8
const MAX_PASSWORD = 32

const Password = size(
  string(),
  MIN_PASSWORD,
  MAX_PASSWORD
)

Централизация ограничений

export const LIMITS = {
  TITLE_MIN: 5,
  TITLE_MAX: 100,
  TAGS_MAX: 10
}

Разделение структур

const TagList = size(array(string()), 1, 10)

const Article = object({
  tags: TagList
})

Поддерживаемые типы

size работает со структурами, имеющими:

  • length
  • size

Обычно это:

Тип Поддержка
String Да
Array Да
Set Да
Map Да
TypedArray Да

TypedArray

const Buffer8 = size(uint8array(), 8)

Проверка:

new Uint8Array(8)

Динамические ограничения

function createLimitedArray(max) {
  return size(array(string()), 1, max)
}

const Tags = createLimitedArray(20)

Интеграция с формами

const RegistrationForm = object({
  login: size(string(), 3, 20),
  password: size(string(), 8, 64),
  hobbies: size(array(string()), 1, 5)
})

Интеграция с REST API

const CreatePostPayload = object({
  title: size(string(), 1, 120),
  content: size(string(), 1, 5000),
  tags: size(array(string()), 0, 10)
})

Интеграция с конфигурациями

const Config = object({
  servers: size(array(string()), 1),
  apiKey: size(string(), 32)
})

Проверка массивов без пустых элементов

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

const Tags = refine(
  size(array(string()), 1, 10),
  'Tags',
  value => {
    return value.every(v => v.length > 0)
  }
)

Валидация URL-массивов

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

const Urls = size(
  array(
    pattern(string(), /^https?:\/\//)
  ),
  1,
  20
)

Сравнение с ручной проверкой

Обычный JavaScript

if (
  !Array.isArray(tags) ||
  tags.length < 1 ||
  tags.length > 10
) {
  throw new Error('Invalid tags')
}

Superstruct

const Tags = size(array(string()), 1, 10)

Преимущества:

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