Типы date и bigint

В Zod работа с датами реализована через z.date(), который описывает значение как экземпляр JavaScript Date и проверяет его на уровне runtime. В отличие от строковых представлений дат, здесь отсутствует необходимость вручную разбирать формат ISO или учитывать особенности парсинга, так как проверка происходит по факту принадлежности к типу Date.

Базовая схема даты определяется следующим образом:

import { z } from "zod";

const DateSchema = z.date();

Такая схема принимает только валидные объекты Date. Любые строковые представления, числа или некорректные значения будут отклонены.

Проверка корректности объекта Date

В JavaScript объект Date может существовать даже в некорректном состоянии:

new Date("invalid");

Такой объект имеет значение NaN внутри и считается невалидной датой. Zod учитывает это поведение и дополнительно проверяет корректность временного значения:

const schema = z.date();

schema.parse(new Date()); // OK
schema.parse(new Date("2020-01-01")); // OK
schema.parse(new Date("invalid date")); // ошибка

Таким образом, проверка включает два уровня:

  • принадлежность к типу Date
  • валидность временного значения (!isNaN(date.getTime()))

Строгая типизация и вывод типов

При использовании z.date() тип выводится автоматически:

type T = z.infer<typeof schema>;
// T = Date

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

Ограничения и уточнения диапазонов

Zod позволяет накладывать дополнительные ограничения на временные значения:

const schema = z.date().min(new Date("2020-01-01")).max(new Date("2030-01-01"));

Логика работы основана на сравнении временных меток:

  • min проверяет, что date >= minDate
  • max проверяет, что date <= maxDate

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

Преобразование входных данных в Date

z.date() не выполняет автоматический парсинг строк. Следующий код приведёт к ошибке:

schema.parse("2024-01-01");

Для обработки строк используется предварительное преобразование:

const schema = z.preprocess((val) => {
  if (typeof val === "string" || typeof val === "number") {
    return new Date(val);
  }
  return val;
}, z.date());

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

BigInt в Zod

Тип bigint предназначен для работы с целыми числами произвольной длины. В Zod он представлен через z.bigint() и соответствует JavaScript-типу BigInt.

const schema = z.bigint();

Базовая проверка BigInt

Схема принимает только значения типа bigint:

schema.parse(10n); // OK
schema.parse(BigInt(10)); // OK
schema.parse(10); // ошибка
schema.parse("10"); // ошибка

Это связано с тем, что BigInt неявно не совместим с number и string.

Проблема сериализации и JSON

BigInt не поддерживается в JSON:

JSON.stringify(10n); // ошибка

Поэтому при работе с API требуется преобразование. Zod предоставляет возможность трансформации:

const schema = z.bigint().transform((val) => val.toString());

Теперь результат может безопасно сериализоваться:

schema.parse(10n); // "10"

Обратное преобразование также часто необходимо:

const schema = z.preprocess((val) => {
  if (typeof val === "string") return BigInt(val);
  return val;
}, z.bigint());

Преобразование из строк и чисел

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

const schema = z.union([z.string(), z.number(), z.bigint()])
  .transform((val) => BigInt(val));

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

Ограничения значений BigInt

Zod поддерживает логические ограничения:

const schema = z.bigint().min(100n).max(1000n);

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

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

Дополнительные ограничения реализуются через refine:

const evenBigInt = z.bigint().refine((val) => val % 2n === 0n, {
  message: "Значение должно быть чётным"
});

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

Сравнение Date и BigInt в Zod

Оба типа относятся к примитивам с особой семантикой:

  • Date опирается на временную шкалу и миллисекунды от Unix epoch
  • BigInt опирается на целочисленную арифметику произвольной точности

При этом Zod обрабатывает их принципиально по-разному:

  • z.date() требует валидного объекта Date
  • z.bigint() требует значения типа bigint

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

Особенности поведения при парсинге

При использовании safeParse поведение остаётся предсказуемым:

const result = z.date().safeParse("2020-01-01");

Результат:

{
  success: false,
  error: ZodError
}

Для bigint аналогично:

z.bigint().safeParse("10");

Также возвращает ошибку, если не добавлена предварительная обработка.

Комбинирование с другими типами

Date и BigInt часто используются в составе сложных объектов:

const schema = z.object({
  createdAt: z.date(),
  updatedAt: z.date(),
  version: z.bigint()
});

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

Трансформации и нормализация данных

Zod позволяет объединять валидацию и преобразование:

const schema = z.object({
  createdAt: z.string().transform((val) => new Date(val)),
  id: z.number().transform((val) => BigInt(val))
});

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

Влияние на TypeScript-типизацию

Для Date и BigInt вывод типов остаётся строгим:

type A = z.infer<typeof z.date()>;
// Date

type B = z.infer<typeof z.bigint()>;
// bigint

Это позволяет сохранять согласованность между runtime-валидацией и compile-time типами без дополнительных аннотаций.

Практические ограничения

При работе с Date и BigInt важно учитывать поведение внешних систем:

  • JSON API не поддерживает Date и BigInt напрямую
  • Базы данных часто возвращают даты строками
  • Некоторые драйверы не поддерживают BigInt без кастов

Поэтому схемы Zod обычно дополняются слоями преобразования на границе системы, тогда как внутри приложения сохраняются строгие типы Date и bigint.

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

Ошибки валидации содержат структурированную информацию:

  • путь до поля
  • ожидаемый тип
  • фактическое значение

Для Date дополнительно может фиксироваться невалидное временное значение, для BigInt — несоответствие типу или переполнение при касте из number.

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