Qué es Zod
Zod es una biblioteca de declaración y validación de esquemas con TypeScript como prioridad. Con solo definir un esquema, puedes realizar validación e inferencia de tipos simultáneamente.
Nuevas Características de Zod 4
Mejoras de Rendimiento
Velocidad de validación:
- Zod 3: 100,000 ops/seg
- Zod 4: 300,000 ops/seg (3 veces más rápido)
Velocidad de parseo:
- Hasta 5 veces más rápido con esquemas complejos
Nueva API de Metadatos
import { z } from 'zod';
const userSchema = z.object({
name: z.string().describe('Nombre del usuario'),
email: z.string().email().describe('Correo electrónico'),
age: z.number().min(0).max(150).describe('Edad')
}).describe('Información del usuario');
// Obtener metadatos
const metadata = userSchema.description;
const fields = userSchema.shape;
Uso Básico
Definición de Esquemas
import { z } from 'zod';
// Tipos primitivos
const stringSchema = z.string();
const numberSchema = z.number();
const booleanSchema = z.boolean();
const dateSchema = z.date();
// Objetos
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
age: z.number().int().positive().optional(),
role: z.enum(['user', 'admin']),
createdAt: z.date().default(() => new Date())
});
// Inferencia de tipos
type User = z.infer<typeof userSchema>;
// {
// id: number;
// name: string;
// email: string;
// age?: number;
// role: 'user' | 'admin';
// createdAt: Date;
// }
Validación
// parse: Lanza una excepción en caso de fallo
const user = userSchema.parse({
id: 1,
name: 'Alice',
email: 'alice@example.com',
role: 'user'
});
// safeParse: Devuelve el resultado como objeto
const result = userSchema.safeParse(input);
if (result.success) {
console.log(result.data);
} else {
console.error(result.error.issues);
}
Transformación (Transform)
const schema = z.string()
.transform(val => val.toLowerCase())
.transform(val => val.trim());
const cleanSchema = z.object({
price: z.string().transform(val => parseFloat(val)),
quantity: z.string().transform(val => parseInt(val, 10))
});
Características Avanzadas
Refinamiento
const passwordSchema = z.string()
.min(8, 'La contraseña debe tener al menos 8 caracteres')
.refine(
(val) => /[A-Z]/.test(val),
{ message: 'Debe incluir una letra mayúscula' }
)
.refine(
(val) => /[0-9]/.test(val),
{ message: 'Debe incluir un número' }
);
// superRefine (devuelve múltiples errores)
const formSchema = z.object({
password: z.string(),
confirmPassword: z.string()
}).superRefine((data, ctx) => {
if (data.password !== data.confirmPassword) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Las contraseñas no coinciden',
path: ['confirmPassword']
});
}
});
Uniones y Discriminadores
// Unión normal
const responseSchema = z.union([
z.object({ status: z.literal('success'), data: z.any() }),
z.object({ status: z.literal('error'), message: z.string() })
]);
// Unión discriminada (más rápida)
const eventSchema = z.discriminatedUnion('type', [
z.object({ type: z.literal('click'), x: z.number(), y: z.number() }),
z.object({ type: z.literal('scroll'), offset: z.number() }),
z.object({ type: z.literal('keypress'), key: z.string() })
]);
Esquemas Recursivos
interface Category {
name: string;
subcategories: Category[];
}
const categorySchema: z.ZodType<Category> = z.lazy(() =>
z.object({
name: z.string(),
subcategories: z.array(categorySchema)
})
);
Parcial y Requerido
const userSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string()
});
// Hacer todo opcional
const partialUser = userSchema.partial();
// Solo campos específicos opcionales
const updateUser = userSchema.partial({
name: true,
email: true
});
// Convertir opcionales en requeridos
const requiredUser = userSchema.required();
Validación de API
Express
import express from 'express';
import { z } from 'zod';
const createUserSchema = z.object({
body: z.object({
name: z.string(),
email: z.string().email()
}),
query: z.object({
notify: z.string().optional()
})
});
function validate<T extends z.ZodType>(schema: T) {
return (req: Request, res: Response, next: NextFunction) => {
const result = schema.safeParse(req);
if (!result.success) {
return res.status(400).json({ errors: result.error.issues });
}
next();
};
}
app.post('/users', validate(createUserSchema), (req, res) => {
// Ya validado
});
tRPC
import { z } from 'zod';
import { publicProcedure, router } from './trpc';
export const appRouter = router({
createUser: publicProcedure
.input(z.object({
name: z.string().min(1),
email: z.string().email()
}))
.mutation(async ({ input }) => {
return db.user.create({ data: input });
})
});
Integración con Bibliotecas de Formularios
React Hook Form
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
name: z.string().min(1, 'El nombre es requerido'),
email: z.string().email('Ingresa un correo electrónico válido')
});
function Form() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema)
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('name')} />
{errors.name && <span>{errors.name.message}</span>}
{/* ... */}
</form>
);
}
Resumen
Zod 4 ha hecho que la validación de esquemas en TypeScript sea aún más rápida y fácil de usar. Con su integración de inferencia de tipos, ricas funciones de validación y compatibilidad con frameworks, es una herramienta indispensable para el desarrollo de aplicaciones type-safe.
← Volver a la lista