Zod is the TypeScript-first schema validation library. Most developers use z.object() and z.string() — but Zod ships with powerful APIs that can replace entire validation libraries.
The Free APIs You're Missing
1. z.discriminatedUnion() — Type-Safe Union Parsing
const EventSchema = z.discriminatedUnion("type", [
z.object({ type: z.literal("click"), x: z.number(), y: z.number() }),
z.object({ type: z.literal("keypress"), key: z.string(), code: z.number() }),
z.object({ type: z.literal("scroll"), delta: z.number() }),
]);
type Event = z.infer<typeof EventSchema>;
// Event is automatically: { type: "click"; x: number; y: number } | { type: "keypress"; ... } | ...
40x faster than z.union() — Zod checks the discriminator field first.
2. z.transform() — Parse AND Transform
const DateFromString = z.string()
.transform((s) => new Date(s))
.pipe(z.date().min(new Date("2020-01-01")));
const SlugFromTitle = z.string()
.transform((s) => s.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, ""));
const PriceInCents = z.string()
.regex(/^\d+\.\d{2}$/)
.transform((s) => Math.round(parseFloat(s) * 100));
PriceInCents.parse("19.99"); // 1999
3. z.preprocess() — Clean Data Before Validation
const QueryParams = z.object({
page: z.preprocess((v) => Number(v) || 1, z.number().min(1)),
limit: z.preprocess((v) => Number(v) || 10, z.number().min(1).max(100)),
search: z.preprocess((v) => (v === "" ? undefined : v), z.string().optional()),
tags: z.preprocess(
(v) => (typeof v === "string" ? v.split(",") : v),
z.array(z.string()).default([])
),
});
QueryParams.parse({ page: "3", limit: "25", search: "", tags: "js,ts" });
// { page: 3, limit: 25, search: undefined, tags: ["js", "ts"] }
4. z.custom() — Domain-Specific Types
const EmailAddress = z.string().email().brand<"Email">();
const UserId = z.string().uuid().brand<"UserId">();
const Money = z.number().positive().brand<"Money">();
type Email = z.infer<typeof EmailAddress>; // string & { __brand: "Email" }
type UserId = z.infer<typeof UserId>; // string & { __brand: "UserId" }
// Now TypeScript prevents mixing up strings!
function sendEmail(to: Email, from: Email) { /* ... */ }
// sendEmail(userId, email) → TypeScript ERROR
5. z.lazy() — Recursive Schemas
interface Category {
name: string;
children: Category[];
}
const CategorySchema: z.ZodType<Category> = z.object({
name: z.string(),
children: z.lazy(() => CategorySchema.array()),
});
// Validates deeply nested tree structures
CategorySchema.parse({
name: "Electronics",
children: [
{ name: "Phones", children: [
{ name: "iPhone", children: [] },
]},
],
});
Getting Started
npm install zod
Need data from any website delivered as clean JSON? I build production web scrapers that handle anti-bot, proxies, and rate limits. 77 scrapers running in production. Email me: Spinov001@gmail.com
Check out my awesome-web-scraping list for the best scraping tools and resources.
Top comments (0)