Работа с TypeScript

Библиотека date-fns изначально проектировалась с ориентацией на строгую типизацию, что делает её удобной для использования в TypeScript-проектах без дополнительных обёрток и деклараций типов. Каждая функция экспортирует явно описанные сигнатуры, что позволяет компилятору выводить корректные типы на основании входных аргументов.

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

function addDays(date: Date | number, amount: number): Date

Первый аргумент почти всегда допускает Date | number, где число интерпретируется как timestamp (миллисекунды Unix-времени). Возвращаемое значение — новый экземпляр Date, что подчёркивает неизменяемость операций.

Ключевая особенность — отсутствие мутирующих операций. Типы это отражают: исходные данные не изменяются, результат всегда возвращается отдельно.


Работа с базовыми типами Date

TypeScript-совместимость обеспечивается через унифицированный подход к входным параметрам. Практически все функции принимают:

  • Date
  • number (timestamp)
  • иногда string (в ограниченных парсинг-функциях)

Пример типизированного использования:

import { format, addMonths } from "date-fns";

const start: Date = new Date(2024, 0, 1);
const result: Date = addMonths(start, 3);

const label: string = format(result, "yyyy-MM-dd");

Компилятор фиксирует корректность типов на уровне вызова функций. Ошибочные конструкции, например передача объектов или строк в арифметические функции, приводят к ошибкам компиляции.


Перегрузки функций и строгие сигнатуры

Многие функции date-fns используют перегрузки для обеспечения гибкости без потери типовой безопасности.

Пример:

declare function parse(
  dateString: string,
  formatString: string,
  referenceDate: Date
): Date;

declare function parse(
  dateString: string,
  formatString: string,
  referenceDate: number
): Date;

Перегрузки позволяют корректно обрабатывать разные типы referenceDate, сохраняя единый возвращаемый тип.

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


Работа с опциональными параметрами

В date-fns активно используются опциональные параметры, особенно в функциях форматирования и локализации.

import { format } from "date-fns";
import { ru } from "date-fns/locale";

const d: Date = new Date();

const s1: string = format(d, "PP");
const s2: string = format(d, "PP", { locale: ru });

Тип опций описывается через интерфейсы:

interface FormatOptions {
  locale?: Locale;
  weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
  firstWeekContainsDate?: number;
}

Строгая типизация ограничивает допустимые значения, например для weekStartsOn используется union-тип.


Импорт типов и модульная структура

date-fns полностью поддерживает ES Modules и TypeScript module resolution.

Типы встроены в пакет, поэтому отдельная установка @types/date-fns не требуется.

Пример структуры импортов:

import { addDays, differenceInDays } from "date-fns";

Tree-shaking сохраняется, поскольку каждый модуль экспортируется отдельно. TypeScript корректно анализирует такие импорты и не включает лишний код в сборку.


Типизация локалей и интернационализация

Локали в date-fns представляют собой строго типизированные объекты Locale.

import { Locale } from "date-fns";
import { enUS, de, ru } from "date-fns/locale";

const locale: Locale = ru;

Тип Locale включает:

  • форматирование месяцев и дней
  • правила склонений
  • настройки первого дня недели
  • внутренние функции formattingTokens

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


Функциональный стиль (FP) и типы

date-fns предоставляет функциональный API в стиле FP через подмодуль date-fns/fp. Он отличается каррированием функций и изменённым порядком аргументов.

import { addDays, format } from "date-fns/fp";

const addTenDays = addDays(10);

const result: string = format("yyyy-MM-dd", addTenDays(new Date()));

Типизация FP-версии строится через обобщённые функции высшего порядка:

type CurriedAddDays = (amount: number) => (date: Date) => Date;

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


Работа с null, undefined и strict режимом

TypeScript в связке с date-fns обычно используется в режиме strict: true, что усиливает контроль типов.

Функции date-fns не принимают null или undefined в качестве валидных дат:

addDays(null as any, 5); // потенциальная ошибка типизации

В строгом режиме подобные конструкции блокируются на этапе компиляции.

Для обработки неопределённых значений применяется явная нормализация:

const safeDate: Date = inputDate ?? new Date();
const updated: Date = addDays(safeDate, 7);

Типизация парсинга и валидации дат

Функции парсинга возвращают Date, но не выполняют автоматическую валидацию на уровне типов, что отражается в контракте:

function parseISO(argument: string): Date;

TypeScript не различает корректные и некорректные даты на уровне типов, поэтому результат всегда остаётся Date, даже если он может быть невалидным (Invalid Date).

Для этого применяется вспомогательная проверка:

import { isValid } from "date-fns";

const d: Date = parseISO("2024-13-40");

const ok: boolean = isValid(d);

Тип boolean отделяет этап проверки от этапа использования значения.


Обобщённые типы и расширяемость

Некоторые внутренние механизмы date-fns используют generics для сохранения информации о типах входных параметров:

type DateArg<DateType extends Date = Date> = DateType | number;

Это позволяет сохранять совместимость с расширенными типами даты в пользовательских обёртках или альтернативных реализациях Date.


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

Работа с диапазонами дат использует строго описанные структуры:

interface Interval {
  start: Date | number;
  end: Date | number;
}

Функции, работающие с интервалами, принимают только этот контракт:

import { isWithinInterval } from "date-fns";

const interval: Interval = {
  start: new Date(2024, 0, 1),
  end: new Date(2024, 11, 31),
};

const result: boolean = isWithinInterval(new Date(), interval);

Типизация гарантирует наличие обоих полей, исключая частично определённые структуры.


Совместимость с lib.dom и встроенными типами

date-fns не конфликтует с DOM-типами TypeScript. Использование Date из стандартной библиотеки обеспечивает единый контракт между браузером и Node.js.

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


Вывод типов при композиции функций

При комбинировании функций TypeScript корректно выводит промежуточные типы:

import { addDays, format } from "date-fns";

const transform = (d: Date): string =>
  format(addDays(d, 5), "yyyy-MM-dd");

Тип вывода определяется как:

  • вход: Date
  • промежуточный результат: Date
  • итог: string

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


Типы ошибок и отсутствие исключений в сигнатурах

date-fns не моделирует ошибки через исключения в типах. Все функции остаются чистыми с точки зрения сигнатур:

  • нет throws в TypeScript декларациях
  • нет Result<T, E> типов
  • ошибки выражаются через возвращаемые значения (Invalid Date, false)

Такой подход упрощает интеграцию с существующими типовыми системами TypeScript и снижает необходимость обработки исключений на уровне типов.