Zod Is a Swiss Army Knife
Most developers use Zod for form validation. But it can do much more: generate types, transform data, build API schemas, and more.
1. Generate TypeScript Types Automatically
import { z } from "zod";
const UserSchema = z.object({
name: z.string().min(1),
email: z.string().email(),
age: z.number().min(0).max(150),
role: z.enum(["admin", "user", "moderator"])
});
// Auto-generate TypeScript type
type User = z.infer<typeof UserSchema>;
// { name: string; email: string; age: number; role: "admin" | "user" | "moderator" }
Define schema once. Get validation AND types.
2. Transform Data During Validation
const FormInput = z.object({
name: z.string().transform(s => s.trim()),
email: z.string().email().transform(s => s.toLowerCase()),
age: z.string().transform(Number).pipe(z.number().min(0)),
tags: z.string().transform(s => s.split(",").map(t => t.trim()))
});
const result = FormInput.parse({
name: " John ",
email: "JOHN@EXAMPLE.COM",
age: "25",
tags: "dev, python, api"
});
// { name: "John", email: "john@example.com", age: 25, tags: ["dev", "python", "api"] }
3. Validate API Responses
const APIResponse = z.object({
data: z.array(z.object({
id: z.number(),
title: z.string(),
published: z.boolean()
})),
total: z.number(),
page: z.number()
});
async function fetchPosts() {
const res = await fetch("/api/posts");
const json = await res.json();
return APIResponse.parse(json); // Throws if API response is wrong
}
4. Build Discriminated Unions
const Shape = z.discriminatedUnion("type", [
z.object({ type: z.literal("circle"), radius: z.number() }),
z.object({ type: z.literal("square"), side: z.number() }),
z.object({ type: z.literal("rectangle"), width: z.number(), height: z.number() })
]);
const shape = Shape.parse({ type: "circle", radius: 5 }); // OK
Shape.parse({ type: "triangle", sides: 3 }); // Error!
5. Create Recursive Schemas
const Category: z.ZodType<any> = z.object({
name: z.string(),
children: z.lazy(() => z.array(Category)).optional()
});
// Validates nested tree structures
Category.parse({
name: "Root",
children: [
{ name: "Child 1", children: [{ name: "Grandchild" }] },
{ name: "Child 2" }
]
});
Zod vs Alternatives
| Feature | Zod | Yup | Joi |
|---|---|---|---|
| TypeScript-first | Yes | No | No |
| Type inference | Yes | Limited | No |
| Transforms | Yes | Yes | Yes |
| Bundle size | 13KB | 14KB | 27KB |
| Tree-shakable | Yes | Partial | No |
More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs
Top comments (0)