Type Inference
Zod provides powerful type inference capabilities that automatically derive TypeScript types from schema definitions.
Basic Type Inference
ts
import { z } from "zod";
// Basic types
const stringSchema = z.string();
type StringType = z.infer<typeof stringSchema>; // string
const numberSchema = z.number();
type NumberType = z.infer<typeof numberSchema>; // number
const booleanSchema = z.boolean();
type BooleanType = z.infer<typeof booleanSchema>; // boolean
Object Type Inference
ts
const UserSchema = z.object({
id: z.string(),
name: z.string(),
age: z.number().optional(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
// {
// id: string;
// name: string;
// age?: number;
// email: string;
// }
Array and Tuple Type Inference
ts
// Arrays
const stringArraySchema = z.array(z.string());
type StringArray = z.infer<typeof stringArraySchema>; // string[]
// Tuples
const tupleSchema = z.tuple([z.string(), z.number(), z.boolean()]);
type Tuple = z.infer<typeof tupleSchema>; // [string, number, boolean]
Union and Intersection Types
ts
// Union types
const unionSchema = z.union([z.string(), z.number()]);
type Union = z.infer<typeof unionSchema>; // string | number
// Intersection types
const intersectionSchema = z.intersection(
z.object({ name: z.string() }),
z.object({ age: z.number() })
);
type Intersection = z.infer<typeof intersectionSchema>;
// { name: string } & { age: number }
Recursive Type Inference
ts
const CategorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(CategorySchema),
})
);
type Category = z.infer<typeof CategorySchema>;
// {
// name: string;
// subcategories: Category[];
// }
Promise Type Inference
ts
const AsyncSchema = z.promise(z.string());
type AsyncType = z.infer<typeof AsyncSchema>; // Promise<string>
const ComplexAsyncSchema = z.promise(
z.object({
data: z.array(z.string()),
})
);
type ComplexAsync = z.infer<typeof ComplexAsyncSchema>;
// Promise<{ data: string[] }>
Enum Type Inference
ts
// Zod enums
const ZodEnum = z.enum(["A", "B", "C"]);
type ZodEnumType = z.infer<typeof ZodEnum>; // "A" | "B" | "C"
// Native enums
enum NativeEnum {
A = "A",
B = "B",
C = "C",
}
const NativeEnumSchema = z.nativeEnum(NativeEnum);
type NativeEnumType = z.infer<typeof NativeEnumSchema>; // NativeEnum
Type Transformations
ts
const StringToNumber = z.string().transform(val => parseFloat(val));
type TransformedType = z.infer<typeof StringToNumber>; // number
const ComplexTransform = z
.object({
values: z.array(z.string()),
})
.transform(obj => ({
numbers: obj.values.map(Number),
}));
type ComplexTransformed = z.infer<typeof ComplexTransform>;
// { numbers: number[] }
Practical Application
ts
// API response type
const ApiResponse = z.object({
success: z.boolean(),
data: z.union([
z.object({
users: z.array(
z.object({
id: z.string(),
name: z.string(),
})
),
}),
z.object({
error: z.string(),
}),
]),
});
type ApiResponseType = z.infer<typeof ApiResponse>;
// {
// success: boolean;
// data: {
// users: { id: string; name: string; }[];
// } | {
// error: string;
// };
// }
// Using the inferred type
async function fetchUsers(): Promise<ApiResponseType> {
// Implementation...
return {
success: true,
data: {
users: [
{ id: "1", name: "John Doe" },
{ id: "2", name: "Jane Doe" },
],
},
};
}