DEV Community

Alex Spinov
Alex Spinov

Posted on

Zod Is Not Just Validation — 5 Things You Did Not Know It Could Do

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" }
Enter fullscreen mode Exit fullscreen mode

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"] }
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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!
Enter fullscreen mode Exit fullscreen mode

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" }
  ]
});
Enter fullscreen mode Exit fullscreen mode

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 | GitHub


More from me: 10 Dev Tools I Use Daily | 77 Scrapers on a Schedule | 150+ Free APIs

Top comments (0)