В Zod работа с датами реализована через z.date(),
который описывает значение как экземпляр JavaScript Date и
проверяет его на уровне runtime. В отличие от строковых представлений
дат, здесь отсутствует необходимость вручную разбирать формат ISO или
учитывать особенности парсинга, так как проверка происходит по факту
принадлежности к типу Date.
Базовая схема даты определяется следующим образом:
import { z } from "zod";
const DateSchema = z.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 >= minDatemax проверяет, что date <= maxDateЭто делает возможным строгий контроль диапазонов дат, например для бизнес-логики или ограничений API.
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 он представлен через z.bigint() и
соответствует JavaScript-типу BigInt.
const schema = z.bigint();
Схема принимает только значения типа bigint:
schema.parse(10n); // OK
schema.parse(BigInt(10)); // OK
schema.parse(10); // ошибка
schema.parse("10"); // ошибка
Это связано с тем, что BigInt неявно не совместим с
number и string.
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.
Zod поддерживает логические ограничения:
const schema = z.bigint().min(100n).max(1000n);
Операции сравнения выполняются напрямую над значениями
BigInt, что обеспечивает точность без потерь, характерных
для number.
Дополнительные ограничения реализуются через refine:
const evenBigInt = z.bigint().refine((val) => val % 2n === 0n, {
message: "Значение должно быть чётным"
});
Такая конструкция позволяет вводить произвольные математические условия.
Оба типа относятся к примитивам с особой семантикой:
Date опирается на временную шкалу и миллисекунды от
Unix epochBigInt опирается на целочисленную арифметику
произвольной точностиПри этом Zod обрабатывает их принципиально по-разному:
z.date() требует валидного объекта
Datez.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, чтобы отделить этап нормализации
от валидации.
Для Date и BigInt вывод типов остаётся
строгим:
type A = z.infer<typeof z.date()>;
// Date
type B = z.infer<typeof z.bigint()>;
// bigint
Это позволяет сохранять согласованность между runtime-валидацией и compile-time типами без дополнительных аннотаций.
При работе с Date и BigInt важно учитывать
поведение внешних систем:
Date и BigInt
напрямуюBigInt без
кастовПоэтому схемы Zod обычно дополняются слоями преобразования на границе
системы, тогда как внутри приложения сохраняются строгие типы
Date и bigint.
Ошибки валидации содержат структурированную информацию:
Для Date дополнительно может фиксироваться невалидное
временное значение, для BigInt — несоответствие типу или
переполнение при касте из number.
Такая структура позволяет точно локализовать проблему без дополнительного анализа входных данных.