Значения по умолчанию позволяют автоматически подставлять данные,
если поле отсутствует или имеет значение undefined. В
библиотеке Zod для этого используется метод .default().
Подход особенно полезен при:
.default()Базовый синтаксис:
import { z } from "zod";
const schema = z.string().default("guest");
Если входное значение отсутствует:
schema.parse(undefined);
Результат:
"guest"
Если значение передано:
schema.parse("admin");
Результат:
"admin"
.default()Метод .default() срабатывает только в двух случаях:
undefined.Пример:
const schema = z.number().default(100);
schema.parse(undefined); // 100
Но:
schema.parse(null);
Ошибка:
ZodError
null не считается отсутствующим значением.
const usernameSchema = z.string().default("anonymous");
usernameSchema.parse(undefined);
Результат:
"anonymous"
Комбинация с ограничениями:
const schema = z
.string()
.min(3)
.max(20)
.default("guest");
Важно понимать порядок обработки:
default;Если значение по умолчанию не проходит проверку:
const schema = z.string().min(10).default("abc");
Ошибка возникнет даже без входных данных:
schema.parse(undefined);
const schema = z.number().default(0);
schema.parse(undefined);
Результат:
0
С диапазоном:
const ageSchema = z
.number()
.min(0)
.max(120)
.default(18);
const schema = z.boolean().default(false);
Пример:
schema.parse(undefined); // false
schema.parse(true); // true
Типичный случай — флаги конфигурации:
const configSchema = z.object({
debug: z.boolean().default(false),
cache: z.boolean().default(true),
});
const schema = z.array(z.string()).default([]);
Пример:
schema.parse(undefined);
Результат:
[]
Массив может содержать сложные структуры:
const tagsSchema = z
.array(
z.object({
name: z.string(),
})
)
.default([]);
const userSchema = z.object({
name: z.string().default("Unknown"),
age: z.number().default(18),
});
Пример:
userSchema.parse({});
Результат:
{
name: "Unknown",
age: 18
}
Одна из главных особенностей Zod — возможность комбинировать переданные данные и значения по умолчанию.
const settingsSchema = z.object({
theme: z.string().default("light"),
notifications: z.boolean().default(true),
language: z.string().default("en"),
});
Входные данные:
{
theme: "dark"
}
Результат:
{
theme: "dark",
notifications: true,
language: "en"
}
.default() и
.optional()Часто возникает вопрос: нужен ли .optional() вместе с
.default()?
Обычно — нет.
const schema = z.string().default("guest");
Такое поле уже допускает отсутствие значения.
Следующий код избыточен:
z.string().optional().default("guest");
.optional() и .default().optional()Разрешает отсутствие поля.
const schema = z.string().optional();
schema.parse(undefined);
Результат:
undefined
.default()Подставляет конкретное значение.
const schema = z.string().default("guest");
schema.parse(undefined);
Результат:
"guest"
.default()Метод поддерживает функцию-генератор.
const schema = z.string().default(() => crypto.randomUUID());
Каждый вызов parse создаёт новое значение:
schema.parse(undefined);
Результат:
"f47ac10b-58cc..."
const schema = z.date().default(() => new Date());
Пример:
schema.parse(undefined);
Результат:
2026-05-09T12:00:00.000Z
const userSchema = z.object({
id: z.string().default(() => crypto.randomUUID()),
name: z.string(),
});
transformdefault может использоваться вместе с
трансформациями.
const schema = z
.string()
.default("42")
.transform((value) => Number(value));
Результат:
schema.parse(undefined); // 42
Последовательность:
preprocessconst schema = z.preprocess(
(value) => {
if (value === "") {
return undefined;
}
return value;
},
z.string().default("empty")
);
Пример:
schema.parse("");
Результат:
"empty"
Подход полезен при обработке HTML-форм, где пустая строка часто означает отсутствие значения.
Одна из самых распространённых областей применения.
const envSchema = z.object({
PORT: z.coerce.number().default(3000),
HOST: z.string().default("localhost"),
DEBUG: z.coerce.boolean().default(false),
});
Использование:
const config = envSchema.parse(process.env);
coercecoerce преобразует входные данные перед валидацией.
const schema = z.coerce.number().default(0);
Пример:
schema.parse("42");
Результат:
42
При отсутствии значения:
schema.parse(undefined);
Результат:
0
const schema = z.object({
user: z.object({
name: z.string().default("Anonymous"),
role: z.string().default("user"),
}),
});
Проблема:
schema.parse({});
Ошибка:
Required at "user"
Причина — объект user обязателен.
Правильный вариант:
const schema = z.object({
user: z
.object({
name: z.string().default("Anonymous"),
role: z.string().default("user"),
})
.default({}),
});
Теперь:
schema.parse({});
Результат:
{
user: {
name: "Anonymous",
role: "user"
}
}
.catch() вместо .default()Методы имеют разное назначение.
.default()Срабатывает только при undefined.
.catch()Срабатывает при ошибке валидации.
Пример:
const schema = z.number().catch(0);
schema.parse("abc");
Результат:
0
Сравнение:
z.number().default(0).parse(undefined); // 0
z.number().catch(0).parse("abc"); // 0
.nullish() и
значения по умолчанию.nullish() разрешает:
null;undefined.const schema = z.string().nullish();
Но default не заменяет null.
const schema = z.string().nullish().default("guest");
schema.parse(undefined); // "guest"
schema.parse(null); // null
nullДля обработки null используется
preprocess.
const schema = z.preprocess(
(value) => value ?? undefined,
z.string().default("guest")
);
Теперь:
schema.parse(null);
Результат:
"guest"
const schema = z.string().default("guest");
type Result = z.infer<typeof schema>;
Тип:
string
Несмотря на возможность отсутствия входного значения, результат после
parse всегда содержит строку.
safeParseconst schema = z.string().default("guest");
const result = schema.safeParse(undefined);
Результат:
{
success: true,
data: "guest"
}
Функция в .default() вызывается только при
необходимости.
const schema = z.string().default(() => {
console.log("generated");
return "value";
});
Пример:
schema.parse("test");
Функция не выполнится.
А здесь выполнится:
schema.parse(undefined);
z.string().email().default("abc");
Ошибка при parse(undefined).
nullz.string().default("x").parse(null);
null не заменяется автоматически.
.default({}) у вложенного объектаconst schema = z.object({
settings: z.object({
dark: z.boolean().default(false),
}),
});
settings остаётся обязательным.
const appConfigSchema = z.object({
appName: z.string().default("My App"),
server: z.object({
host: z.string().default("localhost"),
port: z.number().default(3000),
}).default({}),
features: z.object({
auth: z.boolean().default(true),
analytics: z.boolean().default(false),
}).default({}),
limits: z.object({
maxUsers: z.number().default(1000),
timeout: z.number().default(5000),
}).default({}),
});
Входные данные:
{
server: {
port: 8080
}
}
Результат:
{
appName: "My App",
server: {
host: "localhost",
port: 8080
},
features: {
auth: true,
analytics: false
},
limits: {
maxUsers: 1000,
timeout: 5000
}
}
const createUserSchema = z.object({
name: z.string(),
role: z.enum([
"user",
"admin",
]).default("user"),
isActive: z.boolean().default(true),
createdAt: z.date().default(() => new Date()),
});
Использование:
createUserSchema.parse({
name: "Alex"
});
Результат:
{
name: "Alex",
role: "user",
isActive: true,
createdAt: 2026-05-09T12:00:00.000Z
}