Частичная валидация применяется в ситуациях, когда входные данные содержат не полный набор полей объекта, а только их подмножество. Это характерно для PATCH-запросов, форм редактирования, обновлений сущностей и любых сценариев, где требуется изменить лишь часть структуры, не затрагивая остальные поля.
В библиотеке Zod частичная валидация реализуется через трансформацию схемы объекта, при которой все или часть полей становятся необязательными без изменения базовой структуры данных.
Обычная схема объекта в Zod описывает строгую структуру, где каждое поле является обязательным:
import { z } from "zod";
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string(),
});
Такая схема требует наличия всех трёх полей при валидации.
Метод .partial() изменяет поведение схемы:
const PartialUserSchema = UserSchema.partial();
После применения .partial() каждое поле становится
необязательным, сохраняя при этом типизацию и ограничения значений.
.partial() на уровне типов.partial() преобразует:
{
id: number;
name: string;
email: string;
}
в:
{
id?: number;
name?: string;
email?: string;
}
Ключевой момент заключается в том, что поля не удаляются из схемы, а получают статус optional. Это означает, что при наличии значения оно всё равно проходит валидацию.
При использовании частичной схемы метод safeParse
становится основным инструментом обработки входных данных:
const result = PartialUserSchema.safeParse({
email: "test@mail.com",
});
Результат будет успешным, даже если отсутствуют id и
name, поскольку они не обязательны.
При этом, если поле присутствует, но не соответствует типу, валидация всё равно проваливается:
PartialUserSchema.safeParse({
name: 123,
});
Несмотря на частичность, типовая проверка остаётся строгой.
.partial() не изменяет следующие аспекты:
Это важно при работе со сложными схемами, где ожидается глубокая трансформация.
Для вложенных объектов используется deepPartial:
const Schema = z.object({
user: z.object({
profile: z.object({
age: z.number(),
city: z.string(),
}),
}),
});
const DeepPartialSchema = Schema.deepPartial();
Теперь становятся необязательными не только верхнеуровневые поля, но и все вложенные свойства.
Важно различать два уровня:
.partial() — трансформирует объект, делая все его поля
необязательнымиz.optional() — применяется к конкретному полюПример:
const Schema = z.object({
name: z.string().optional(),
});
Здесь поле name может отсутствовать, но остальные поля
объекта остаются обязательными.
В partial-схеме:
Schema.partial();
объект целиком становится гибким по структуре.
Частичная валидация наиболее естественно применяется в API-методах обновления:
const UpdateUserSchema = UserSchema.partial();
app.patch("/user", (req) => {
const data = UpdateUserSchema.parse(req.body);
});
Такая схема позволяет передавать только изменяемые поля без необходимости дублировать весь объект.
Методы .pick() и .omit() часто
комбинируются с partial-схемами.
const Base = UserSchema.pick({
name: true,
email: true,
}).partial();
В этом случае только выбранные поля становятся optional.
const Base = UserSchema.partial().pick({
name: true,
});
Поведение зависит от порядка вызовов, так как каждый метод возвращает новую схему.
При наличии .default() поведение меняется:
const Schema = z.object({
role: z.string().default("user"),
}).partial();
Если поле role отсутствует во входных данных, оно не
будет автоматически заменено на "user" при валидации.
Default применяется только если поле присутствует в схеме и не
отсутствует как optional без дополнительной обработки.
Поведение строгой проверки влияет на частичные схемы:
UserSchema.partial().strict();
strict() запрещает неизвестные поляpartial() делает известные поля необязательнымиКомбинация часто используется для API, где структура гибкая, но расширение недопустимо.
.partial() не влияет на элементы массивов:
const Schema = z.object({
tags: z.array(z.object({
id: z.number(),
label: z.string(),
})),
}).partial();
Поле tags становится optional, но элементы массива
остаются строго типизированными.
При использовании union-типов:
const Schema = z.union([
z.object({ type: z.literal("a"), value: z.string() }),
z.object({ type: z.literal("b"), value: z.number() }),
]);
.partial() не применяется напрямую ко всему union,
требуется оборачивать каждый вариант отдельно, иначе поведение остаётся
неизменным.
Zod синхронизирует runtime-валидацию с TypeScript типами:
type PartialUser = z.infer<typeof PartialUserSchema>;
Результирующий тип автоматически отражает optional-поля, исключая
необходимость ручного определения Partial
Наиболее частые источники ошибок:
Частичная валидация используется в следующих областях:
В сложных схемах partial часто сочетается с
.transform():
const Schema = UserSchema.partial().transform((data) => ({
...data,
updatedAt: Date.now(),
}));
В этом случае частичные данные дополняются вычисляемыми полями, сохраняя гибкость входа и стабильность выходной структуры.