Головна ідея Zod (і подібних бібліотек) - один опис даних дає і перевірку під час виконання, і тип для компілятора.
import * as z from 'zod';
export const VacancySchema = z.object({
id: z.number().int().positive(),
title: z.string().min(3),
salary: z.number().nullable(),
remote: z.boolean(),
tags: z.array(z.string()).default([]),
publishedAt: z.iso.datetime().transform((value) => new Date(value)),
});
export type Vacancy = z.infer<typeof VacancySchema>;
Vacancy виводиться автоматично - описувати інтерфейс окремо не потрібно, і тип не розійдеться зі схемою.
Вхідний і вихідний тип. Схема може перетворювати дані (transform, default, coerce), тож тип «до» і «після» перевірки різний:
type VacancyInput = z.input<typeof VacancySchema>;
// tags?: string[] | undefined (default - можна не передавати)
// publishedAt: string (рядок до перетворення)
type Vacancy = z.output<typeof VacancySchema>; // те саме, що z.infer
// tags: string[]
// publishedAt: Date
z.input- що схема приймає (дані форми, тіло запиту перед відправкою);z.output/z.infer- що схема повертає після перевірки.
parse чи safeParse:
const vacancy = VacancySchema.parse(data); // кидає ZodError
const result = VacancySchema.safeParse(data);
if (!result.success) {
console.error(z.prettifyError(result.error));
} else {
result.data; // Vacancy
}
safeParse повертає дискримінований тип - після перевірки success TypeScript знає, чи є data чи error.
Корисні можливості Zod 4:
- форматні валідатори на верхньому рівні:
z.email(),z.url(),z.uuid(),z.iso.datetime(); z.coerce.number()- перетворення рядків з форм і URL;.pick(),.omit(),.partial(),.extend()- похідні схеми, як утилітні типи TypeScript;z.strictObject- помилка на зайві поля (звичайнийz.objectїх мовчки прибирає).
Пастки:
- не дублювати тип вручну поряд зі схемою - вони розійдуться;
- перевірка не безкоштовна: великі списки (тисячі записів) перевіряти на кожен запит дорого - інколи досить перевіряти структуру першого рівня або вибірково;
- розмір у збірці: для фронтенду, де важливий кожен кілобайт, є
zod/miniчи Valibot з модульним API.