Типизация форматтеров

В библиотеке Globalize типизация форматтеров опирается на разделение ответственности между механизмом локализации и контрактом возвращаемого значения. Форматтер в контексте Globalize представляет собой фабрику функций, где итоговый результат строго предопределён типом входных данных, набором CLDR-правил и выбранной локалью.

Архитектура форматтеров строится вокруг идеи неизменяемого контракта: каждый форматтер возвращает значение фиксированного типа, зависящее от категории форматирования. Несмотря на динамическую природу JavaScript, внутренняя модель Globalize организует форматтеры как строго специализированные функции, ограниченные доменной областью.

Форматтер создаётся один раз и затем используется многократно, при этом его сигнатура остаётся стабильной:

  • числовые форматтеры возвращают строки;
  • форматтеры дат возвращают строки;
  • форматтеры сообщений возвращают строки;
  • вспомогательные функции (например, plural) возвращают числовые или строковые маркеры в зависимости от конфигурации.

Типизация в данном контексте выражается не через язык выполнения, а через контракт поведения.

Возвращаемые типы и контракт форматтера

Форматтеры Globalize можно рассматривать как функции следующего вида:

  • Formatter<TInput, TResult>

Где:

  • TInput — тип входных данных (number, Date, string, object);
  • TResult — всегда строка в большинстве прикладных сценариев.

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

Это создаёт предсказуемую модель:

  • отсутствие перегрузки возвращаемых типов;
  • отсутствие вариативных return-типов;
  • строгая семантика «вход → локализованная строка».

Типизация числовых форматтеров

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

  • вход: number
  • выход: string

Числовой форматтер учитывает:

  • локаль (разделители тысяч и десятичные знаки);
  • стиль форматирования (decimal, percent, currency);
  • опциональные параметры точности.

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

Пример логики типового контракта:

  • numberFormatter() → функция (n: number) => string
  • результат всегда строка, независимо от конфигурации валюты или процентов.

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

Типизация форматтеров дат и времени

Форматтеры дат в Globalize используют аналогичную модель строгого преобразования:

  • вход: Date
  • выход: string

Несмотря на наличие различных шаблонов (short, medium, long, full), тип возвращаемого значения остаётся неизменным.

Типовая модель:

  • dateFormatter(options)(date: Date) => string

Строгая типизация обеспечивается следующими правилами:

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

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

Типизация message-форматтеров

Message formatter представляет собой более сложный типовой случай, так как он включает интерполяцию, plural-правила и выбор ветвления.

Формально:

  • вход: object
  • выход: string

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

  • параметры сообщений имеют ключи строкового типа;
  • значения параметров могут быть string | number | Date.

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

  • TParams = Record<string, string | number | Date>

Несмотря на это, итоговый тип результата остаётся фиксированным:

  • string

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

Статическая и динамическая типизация

В TypeScript-интеграциях Globalize типизация форматтеров описывается через обобщённые интерфейсы, однако сама библиотека не навязывает строгие compile-time ограничения.

Типовая модель:

  • статическая типизация применяется на уровне оболочек;
  • динамическая типизация сохраняется внутри runtime.

Это создаёт гибридную систему:

  • на этапе разработки фиксируется сигнатура форматтера;
  • на этапе выполнения происходит интерпретация CLDR-правил.

Типизация кастомных форматтеров

Кастомные форматтеры расширяют систему типов через обобщённые интерфейсы функций:

  • (value: T) => string

При этом тип T зависит от доменной области:

  • финансовые значения: number
  • идентификаторы: string
  • агрегированные структуры: object

Главное ограничение заключается в унификации результата:

  • любой кастомный форматтер обязан возвращать string.

Это позволяет сохранять совместимость с системой message formatting и цепочками локализации.

Инварианты типовой системы

Типизация форматтеров строится на нескольких инвариантах:

  • отсутствие множественных return-типов;
  • отсутствие перегрузки результата по локали;
  • строгая нормализация входных данных;
  • неизменяемость функции после создания.

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

Типизация в цепочках форматирования

Форматтеры могут использоваться в композиции, где результат одного становится входом другого. При этом типовая модель сохраняет следующее правило:

  • промежуточные результаты всегда string.

Таким образом цепочка форматирования выглядит типово однородной:

  • number → string → message interpolation → string

Отсутствие промежуточных нетипизированных структур снижает риск несоответствия типов в сложных локализационных сценариях.

Ограничения типизации

Типовая система форматтеров не является полной в смысле статической проверки:

  • отсутствует строгая проверка CLDR-опций на уровне типов;
  • параметры локали не типизированы как конечное множество;
  • нет проверки соответствия шаблонов сообщений типам параметров на уровне runtime.

В результате типизация описывает только верхний уровень:

  • входные данные;
  • выходные данные;
  • базовую структуру параметров.

Внутренняя семантика локализации остаётся динамической.