Zod is a TypeScript-first schema declaration and validation library. You define schemas that validate data at runtime, while also inferring TypeScript types automatically.
Example:
import { z } from "zod";
const UserSchema = z.object({
id: z.string(),
age: z.number().min(18),
email: z.string().email(),
});
Here UserSchema
validates that an object has a string id
, a number age
≥ 18, and a valid email
.
Type Inference in Zod
The key feature: you do not need to manually define a matching TypeScript type. Instead, you extract it from the schema.
type User = z.infer<typeof UserSchema>;
Now User
is equivalent to:
type User = {
id: string;
age: number;
email: string;
};
This ensures runtime checks (Zod validation) and compile-time safety (TypeScript typing) are always consistent.
Why Use Zod Inference?
- Eliminates duplication: No need to manually sync types and validation.
- Ensures safety: If you change the schema, the type updates automatically.
- Improves maintainability: One source of truth for both runtime and type-level constraints.
Practical Example
const TodoSchema = z.object({
title: z.string().min(3),
completed: z.boolean(),
dueDate: z.date().optional(),
});
// inferred type
type Todo = z.infer<typeof TodoSchema>;
const data: unknown = {
title: "Learn Zod",
completed: true,
};
const parsed = TodoSchema.parse(data); // ✅ runtime validation
-
parsed
has typeTodo
. - If
data
fails validation, Zod throws an error. - The TypeScript compiler knows
parsed.title
is a string,parsed.completed
is a boolean, andparsed.dueDate
may beDate | undefined
.
Advanced Inference Cases
- Union Types
const StatusSchema = z.union([z.literal("active"), z.literal("inactive")]);
type Status = z.infer<typeof StatusSchema>; // "active" | "inactive"
- Arrays
const Numbers = z.array(z.number());
type NumbersType = z.infer<typeof Numbers>; // number[]
- Nested Objects
const Profile = z.object({
user: UserSchema,
hobbies: z.array(z.string()),
});
type ProfileType = z.infer<typeof Profile>;
Conclusion
Zod inference bridges runtime validation with static type safety. Instead of maintaining separate validation logic and TypeScript interfaces, you define schemas once and extract types automatically. This reduces bugs, prevents mismatches, and accelerates development.
Top comments (0)