В JavaScript числовая модель основана на формате IEEE 754 с плавающей
точкой двойной точности. Это накладывает фундаментальные ограничения на
корректность и предсказуемость работы с числами: существуют значения
Infinity, -Infinity, NaN, а также
ограничение на безопасный диапазон целых чисел — от
-(2^53 - 1) до (2^53 - 1). Эти особенности
напрямую влияют на валидацию данных, особенно в контексте серверных
приложений и API, где требуется строгая типизация входящих значений.
Конечными числами считаются все значения типа number,
которые не являются бесконечностью и не равны NaN. В
стандартной модели JavaScript это проверяется через
Number.isFinite.
В контексте схем валидации такие ограничения критичны, поскольку
Infinity и NaN способны разрушать
бизнес-логику:
NaN распространяется через арифметические операцииInfinity может появляться при делении на нольВ библиотеке Zod конечность числа задаётся через явное ограничение:
import { z } from "zod";
const schema = z.number().finite();
Такая схема гарантирует, что значение проходит проверку
Number.isFinite(value) и исключает все недопустимые
числовые состояния.
Базовая схема:
z.number()
разрешает любые значения типа number, включая:
NaNInfinity-InfinityЭто связано с тем, что JavaScript формально считает их числовым типом.
Использование .finite() добавляет строгую семантику:
z.number().finite()
эквивалентно логике:
(value) => typeof value === "number" && Number.isFinite(value)
Такой уровень строгости особенно важен при работе с финансовыми расчётами, координатами, метриками и любыми вычислениями, где недопустимы неопределённые значения.
JavaScript может безопасно представлять только целые числа в диапазоне:
Number.MIN_SAFE_INTEGER === -(2^53 - 1)
Number.MAX_SAFE_INTEGER === (2^53 - 1)
За пределами этого диапазона арифметика теряет точность:
9007199254740992 === 9007199254740993 // true
Такая потеря точности делает сравнения и идентификаторы ненадёжными.
В Zod для этого используется ограничение безопасных чисел:
const schema = z.number().safe();
или более явно:
z.number().int().safe();
Внутренне это соответствует проверке:
Number.isSafeInteger(value)
Эти ограничения относятся к разным аспектам числовой модели:
z.number().finite()
Отсекает:
Но допускает дробные числа.
z.number().int()
Гарантирует отсутствие дробной части, но не защищает от выхода за пределы безопасного диапазона.
z.number().safe()
Гарантирует, что число:
В реальных схемах часто требуется композиция ограничений:
const idSchema = z.number().int().safe().positive();
Такой подход обеспечивает:
Другой пример для измерений:
const metricSchema = z.number().finite().nonnegative();
Здесь допускаются дробные значения, но исключаются некорректные состояния вычислений.
NaN имеет уникальное поведение:
typeof NaN === "number"NaN !== NaNЭто делает его особенно опасным в системах валидации.
Схема:
z.number()
не исключает NaN.
Схема:
z.number().finite()
исключает его явно.
Таким образом, конечность одновременно решает проблему как
NaN, так и бесконечностей.
Для случаев, выходящих за пределы
Number.MAX_SAFE_INTEGER, используется
BigInt:
const schema = z.bigint();
Особенности:
numberСравнение подходов:
| Тип | Диапазон | Дробные | Потеря точности |
|---|---|---|---|
| number | ограничен | да | да |
| safe integer | ограничен | нет | нет |
| bigint | неограничен | нет | нет |
Комбинация .finite() и .safe() формирует
разные уровни строгости:
finite — контроль корректности вычисленийsafe — контроль точности представленияint — контроль структуры значенияВалидация входных данных без этих ограничений приводит к накоплению ошибок на уровне бизнес-логики, особенно при:
Zod допускает нормализацию значений перед проверкой:
const schema = z.preprocess((val) => {
if (typeof val === "string") return Number(val);
return val;
}, z.number().finite());
Это позволяет отделить этап парсинга от этапа строгой валидации, сохраняя предсказуемость схемы.
При нарушении условий Zod возвращает структурированную ошибку, содержащую:
invalid_type, too_big,
too_small)Для чисел с ограничением конечности тип ошибки фиксируется как
нарушение числового диапазона, поскольку NaN и
Infinity рассматриваются как выход за допустимые пределы
значений.
Внутри Zod числовая система ограничений формирует многоуровневую модель:
numberfiniteintsafeЭти уровни позволяют строить строгие схемы, соответствующие математически корректному представлению данных в условиях ограничений IEEE 754 и особенностей JavaScript-движков.