В библиотеке валидации схем Zod тип null представлен
отдельным примитивом и создаётся через z.null(). Его смысл
строго ограничен: значение должно быть ровно null, без
дополнительных вариантов.
import { z } from "zod";
const NullSchema = z.null();
NullSchema.parse(null); // проходит
NullSchema.parse(undefined); // ошибка
NullSchema.parse(0); // ошибка
NullSchema.parse(""); // ошибка
Ключевая особенность z.null() заключается в том, что он
не допускает никаких альтернатив. В отличие от многих других типов,
здесь отсутствует концепция приведения или преобразования. Проверка
максимально строгая.
Часто null используется в схемах API-ответов, где сервер
явно возвращает отсутствие значения, но не опускает поле полностью. Это
принципиально отличается от undefined.
Пример комбинирования:
const NullableString = z.string().nullable();
NullableString.parse("text"); // ok
NullableString.parse(null); // ok
NullableString.parse(undefined); // ошибка
Метод .nullable() фактически преобразует тип в union:
T | null, но при этом undefined остаётся
недопустимым значением.
undefinedТип undefined в Zod создаётся через
z.undefined(). Он описывает строгое соответствие значению
undefined.
const UndefinedSchema = z.undefined();
UndefinedSchema.parse(undefined); // проходит
UndefinedSchema.parse(null); // ошибка
UndefinedSchema.parse("value"); // ошибка
Семантически undefined чаще всего связан с отсутствием
значения в JavaScript-объектах, особенно при работе с необязательными
полями.
Важная деталь: Zod различает undefined как значение и
отсутствие ключа в объекте. Это влияет на поведение схем объектов:
const Schema = z.object({
name: z.string().optional(),
});
Schema.parse({}); // ok
Schema.parse({ name: undefined }); // ok
Schema.parse({ name: "John" }); // ok
Метод .optional() фактически расширяет тип до
T | undefined.
undefined и null часто используются в
составе объединений, где требуется явно описать все возможные состояния
данных.
const ValueSchema = z.union([
z.string(),
z.null(),
z.undefined(),
]);
Такое объявление фиксирует три различных состояния:
null как явное отсутствие значенияundefined как неинициализированное состояниеНесмотря на внешнюю схожесть, эти состояния несут разную семантику и валидация Zod сохраняет это различие без автоматических преобразований.
voidvoid в Zod представлен через z.void(). Его
поведение отличается от undefined, хотя в JavaScript эти
значения часто путаются.
const VoidSchema = z.void();
VoidSchema.parse(undefined); // проходит
VoidSchema.parse(null); // ошибка
VoidSchema.parse("anything"); // ошибка
z.void() допускает только одно значение —
undefined, но при этом концептуально обозначает «отсутствие
возвращаемого значения», что ближе к сигнатурам функций, чем к
данным.
Использование void наиболее характерно для описания
возвращаемых значений функций:
const LoggerResult = z.void();
function logMessage(msg) {
console.log(msg);
return undefined;
}
LoggerResult.parse(logMessage("test"));
null,
undefined и voidНесмотря на близость в языке JavaScript, Zod рассматривает эти типы как строго разделённые сущности.
| Тип | Разрешённое значение | Семантика |
|---|---|---|
z.null() |
null |
явное отсутствие значения |
z.undefined() |
undefined |
отсутствие инициализации |
z.void() |
undefined |
отсутствие возвращаемого результата |
Такое разделение позволяет моделировать данные с высокой точностью, особенно в API-контрактах и схемах сериализации.
При использовании внутри z.object() различия становятся
особенно заметны.
const Schema = z.object({
a: z.null(),
b: z.undefined(),
c: z.void(),
});
Результаты валидации:
Schema.parse({
a: null,
b: undefined,
c: undefined,
});
Любое отклонение от этих значений приводит к ошибке, включая
отсутствие ключей, если поле не помечено как
.optional().
Zod предоставляет два основных модификатора, которые часто используются вместе со специальными типами:
.optional() → добавляет undefined.nullable() → добавляет nullКомбинации позволяют точно моделировать состояние данных:
const Schema = z.object({
name: z.string().nullable().optional(),
});
Фактически это эквивалентно:
string | null | undefined
Порядок вызова влияет только на читаемость, но не на итоговую семантику.
Zod не выполняет неявных преобразований между null,
undefined и void. Каждое значение проверяется
строго на соответствие.
z.null().parse(undefined); // ошибка
z.undefined().parse(null); // ошибка
z.void().parse(null); // ошибка
Это поведение принципиально отличает Zod от менее строгих валидаторов, где такие значения могут приводиться автоматически.
Одним из ключевых преимуществ Zod является генерация типов:
const schema = z.object({
a: z.null(),
b: z.undefined(),
c: z.void(),
});
type Result = z.infer<typeof schema>;
Результат:
{
a: null;
b?: undefined;
c: undefined;
}
Особенность заключается в том, что void в типах
превращается в undefined, что соответствует поведению
TypeScript, где void фактически является синонимом
undefined в контексте возвращаемых значений.
При работе с JSON:
null сохраняется напрямуюundefined удаляется из JSONvoid не сериализуется и фактически эквивалентен
отсутствию возвращаемого значенияJSON.stringify({
a: null,
b: undefined,
});
Результат:
{"a":null}
Zod учитывает это поведение при проектировании схем, особенно в
API-контрактах, где различие между отсутствующим полем и
null имеет значение.
Комбинации специальных типов часто используются для описания состояний ресурсов:
const UserSchema = z.object({
name: z.string(),
middleName: z.string().nullable(),
nickname: z.string().optional(),
});
Здесь:
null обозначает отсутствие значения, заданное явноundefined — отсутствие поляvoid применяется редко и чаще в функциональных
контекстахconst Schema = z.array(z.null());
Schema.parse([null, null]); // ok
Schema.parse([null, undefined]); // ошибка
Даже внутри коллекций различия сохраняются, что позволяет точно описывать структуры данных без потери информации о состоянии каждого элемента.