Обработка пустых массивов

Поведение Intl.ListFormat при пустом массиве

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

Метод format не вызывает ошибок при передаче пустого массива:

const formatter = new Intl.ListFormat('ru', {
  style: 'long',
  type: 'conjunction'
});

formatter.format([]); // ""

Результат — пустая строка. Это не исключение и не null, а именно строковое значение нулевой длины.

Такое поведение важно учитывать, поскольку логика визуализации списка может неожиданно «исчезнуть», если данные не были проверены.


Причина возврата пустой строки

Intl.ListFormat ориентирован на естественный язык. Пустой список не имеет лингвистического представления. В языковых моделях:

  • нет элементов → нет перечисления
  • нет перечисления → нет текста

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


Опасные сценарии в реальных приложениях

Проблема проявляется в цепочках рендеринга:

const formatter = new Intl.ListFormat('en');

const tags = [];
const result = formatter.format(tags);

console.log(`Tags: ${result}`);

Результат:

Tags:

Семантически это может быть некорректно, поскольку двоеточие остаётся, а содержимое исчезает.


Нормализация пустых массивов

Часто требуется явная обработка до вызова Intl.ListFormat:

function formatList(list, formatter) {
  if (!list || list.length === 0) {
    return '—';
  }
  return formatter.format(list);
}

Такой подход отделяет логику интернационализации от бизнес-правил отображения.


formatToParts и пустые массивы

Метод formatToParts возвращает структурированное представление списка:

const formatter = new Intl.ListFormat('ru');

formatter.formatToParts([]); // []

Результат — пустой массив частей.

Это поведение критично для UI-рендеринга, где ожидается массив сегментов. Отсутствие элементов означает отсутствие структуры, а не ошибку.


Особенности при динамических данных

В приложениях, где данные приходят асинхронно, пустые массивы часто являются промежуточным состоянием:

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

Использование Intl.ListFormat без проверки приводит к невозможности различить:

  • «данных ещё нет»
  • «данные есть, но список пуст»

Сравнение с другими Intl API

Intl.NumberFormat

Пустые массивы здесь не применяются напрямую, но косвенно встречаются при map:

const nf = new Intl.NumberFormat('ru');

[].map(nf.format); // []

Проблема не в Intl, а в том, что форматирование не выполняется.


Intl.Collator

Сортировка пустого массива безопасна:

const collator = new Intl.Collator('ru');

collator.compare; // функция

[].sort(collator.compare); // []

Пустой массив остаётся пустым, что ожидаемо для операций без элементов.


Паттерны безопасной работы

1. Явная подстановка значения по умолчанию
const list = [];

const output = list.length
  ? formatter.format(list)
  : 'Нет элементов';

2. Централизация обработки
function safeFormatList(list, formatter, fallback = '—') {
  return list?.length ? formatter.format(list) : fallback;
}

3. Использование nullish логики данных
const list = data?.tags ?? [];

const output = list.length === 0
  ? '—'
  : formatter.format(list);

Пустые строки как побочный результат локализации

В некоторых локалях форматирование может возвращать строки с пробелами или символами-разделителями, но при пустом массиве поведение стабильно:

  • всегда возвращается пустая строка
  • либо пустой массив частей

Это упрощает предсказуемость API независимо от языка.


Влияние на кеширование и мемоизацию

При мемоизации форматирования списков пустой массив требует отдельного ключа:

const cache = new Map();

function cachedFormat(list, formatter) {
  const key = list.length ? list.join('|') : '__empty__';

  if (cache.has(key)) return cache.get(key);

  const result = list.length ? formatter.format(list) : '';
  cache.set(key, result);

  return result;
}

Без специального ключа возможны конфликты между:

  • пустым массивом
  • массивами с одинаковыми сериализациями

Пустые массивы в конвейерах данных

В функциональных цепочках:

const formatter = new Intl.ListFormat('ru');

const result = data
  .filter(Boolean)
  .map(x => x.label)
  .filter(Boolean)
  .let?.(list => formatter.format(list));

При отсутствии элементов результат становится пустой строкой, что может ломать последующие операции строковой агрегации.


Особенности восприятия в UI-слое

Пустая строка после format([]) часто приводит к:

  • исчезновению блока интерфейса
  • сохранению разделителей (запятых, двоеточий)
  • неконсистентному layout

Поэтому проверка длины массива остаётся обязательной частью интеграции с Intl API.


Взаимодействие с undefined и null

Хотя формально методы Intl ожидают массив строк, на практике:

formatter.format(undefined); // TypeError
formatter.format(null);      // TypeError

Пустой массив отличается тем, что не вызывает ошибки, а возвращает допустимое значение. Это создаёт важное различие:

  • undefined → ошибка
  • null → ошибка
  • [] → валидный, но «пустой» результат

Итоговая модель поведения

Для Intl.ListFormat и связанных сценариев можно выделить устойчивую модель:

  • пустой массив считается валидным входом
  • результат — пустая строка или пустой массив частей
  • ошибки не возникают
  • семантический смысл отсутствует, а не равен «пустому тексту»

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