Zod
1. Introducción
Al trabajar con aplicaciones modernas, garantizar que los datos cumplan ciertos esquemas es crucial. Mientras que TypeScript proporciona tipado estático en tiempo de desarrollo, Zod permite realizar validaciones en tiempo de ejecución, cerrando la brecha que TypeScript no cubre.
Esta guía explora las diferencias, usos y beneficios de Zod y TypeScript, mostrando cómo combinarlos para un desarrollo seguro y robusto.
2. ¿Qué es Zod?
Zod es una biblioteca TypeScript-first para validación de esquemas y tipado en tiempo de ejecución. Su propósito principal es validar datos dinámicos, como respuestas de APIs, datos de formularios o cualquier entrada externa, y generar tipos TypeScript a partir de los esquemas definidos.
3. Ventajas clave de Zod
| Ventaja | Explicación |
|---|---|
| Validación runtime | Zod valida datos en tiempo de ejecución, garantizando que cumplen un esquema definido. |
| Mensajes de error detallados | Proporciona mensajes claros para depuración y manejo de errores en validación. |
| Generación de tipos TypeScript | Crea automáticamente tipos TypeScript a partir de los esquemas definidos en Zod. |
| Soporte asíncrono | Permite validaciones asíncronas para flujos de datos complejos. |
| Composición de esquemas | Facilita la reutilización y combinación de esquemas. |
| Ligero y modular | Es una biblioteca pequeña y fácil de integrar con proyectos existentes. |
3.1 ¿Qué es la validación runtime?
La validación runtime (o validación en tiempo de ejecución) es el proceso de verificar que los datos cumplen con ciertas reglas o restricciones mientras se ejecuta el programa, es decir, cuando los datos están siendo manipulados en el entorno de ejecución (runtime). Esto es particularmente importante para datos dinámicos, como entradas del usuario, respuestas de APIs, o información cargada desde una base de datos, donde no se puede garantizar la forma o validez de los datos hasta que realmente se reciban.
4. Diferencias clave: Zod vs TypeScript
| Aspecto | Zod | TypeScript |
|---|---|---|
| Validación runtime | Sí, valida datos dinámicos durante la ejecución. | No, sólo verifica tipos en tiempo de compilación. |
| Mensajes de error | Detallados y personalizables en caso de datos inválidos. | No genera mensajes de error en tiempo de ejecución. |
| Definición de esquemas | Usa métodos claros para definir y validar esquemas. | Define tipos e interfaces, pero sin validación. |
5. Instalación
Usar Zod en tu proyecto
Primero, instala Zod usando npm o yarn:
npm install zodSi trabajas con TypeScript, asegúrate de tenerlo instalado:
npm install typescript --save-dev6. Ejemplos de Uso
6.1. Validación básica con Zod
import { z } from "zod";
// Definir un esquema para un usuarioconst UserSchema = z.object({ name: z.string(), age: z.number().min(18), // La edad debe ser al menos 18 email: z.string().email(), // Validación de formato de correo});
// Validar datos de entradaconst inputData = { name: "John Doe", age: 25, email: "johndoe@example.com",};
try { const validUser = UserSchema.parse(inputData); // Valida y devuelve el objeto console.log("Usuario válido:", validUser);} catch (e) { console.error("Errores de validación:", e.errors);}6.2. Validación condicional
const ConditionalSchema = z .object({ type: z.enum(["admin", "user"]), permissions: z.array(z.string()).optional(), }) .refine( (data) => { if (data.type === "admin" && !data.permissions) { return false; // Un administrador debe tener permisos } return true; }, { message: "Los administradores deben tener permisos definidos", } );
try { const result = ConditionalSchema.parse({ type: "admin", });} catch (e) { console.error(e.errors);}6.3. Generación de tipos desde esquemas
const ProductSchema = z.object({ id: z.string(), name: z.string(), price: z.number(),});
// Generar un tipo TypeScripttype Product = z.infer<typeof ProductSchema>;
const exampleProduct: Product = { id: "123", name: "Laptop", price: 1200,};6.4. Validaciones asíncronas
Zod permite validar datos de forma asíncrona:
const AsyncSchema = z.string().refine( async (val) => { const exists = await checkIfExists(val); // Función asíncrona personalizada return exists; }, { message: "El valor no existe en la base de datos", });
async function validateAsyncData() { try { await AsyncSchema.parseAsync("some-value"); console.log("Validación exitosa"); } catch (e) { console.error("Errores:", e.errors); }}7. Combinar Zod y TypeScript
La combinación de Zod y TypeScript es ideal cuando necesitas:
- Definir contratos de datos estáticos y dinámicos.
- Validar datos provenientes de fuentes externas.
Ejemplo de integración con APIs:
import axios from "axios";import { z } from "zod";
const ApiResponseSchema = z.object({ id: z.number(), title: z.string(), completed: z.boolean(),});
async function fetchData() { const response = await axios.get( "https://jsonplaceholder.typicode.com/todos/1" );
try { const validData = ApiResponseSchema.parse(response.data); console.log("Datos válidos:", validData); } catch (e) { console.error("Errores de validación:", e.errors); }}fetchData();8. Conclusión
- Zod y TypeScript no compiten, sino que se complementan.
- Mientras TypeScript define contratos estáticos, Zod asegura que los datos dinámicos cumplan los mismos contratos en tiempo de ejecución.
- Juntos, crean aplicaciones más robustas, seguras y mantenibles.