Validación de esquemas de datos con Zod

Zod es una librería para TypeScript que nos permite definir y validar esquemas de datos fácilmente, de forma segura y sin depender de herramientas externas.

validacion-esquemas-datos-zod

Cuando trabajamos con TypeScript, uno de los principales motivos por los que lo usamos es para tener más seguridad al escribir código. TypeScript permite definir tipos, interfaces, estructuras… pero como TypeScript se transpila a JavaScript, todas estas defininciones se pierden en producción. ¿Qué pasa cuando recibimos datos externos —por ejemplo, de una API— y necesitamos verificar que cumplen con ciertas reglas? Ahí es donde entra Zod.

Zod nos permite crear esquemas que validan objetos, arrays, strings, números, fechas y otros tipos de datos. Lo interesante es que los esquemas también actúan como tipos. Eso significa que no necesitamos definir un tipo por un lado y un validador por otro; podemos hacer ambas cosas al mismo tiempo, en el mismo sitio.

Veamos cómo funciona.

Instalación rápida

Podemos instalar Zod usando npm o yarn, como cualquier otra librería:

Terminal
npm install zod

Una vez hecho eso, ya podemos importarlo en nuestro proyecto:

import { z } from 'zod';

Definiendo esquemas y validando datos

Supongamos que queremos validar los datos de un formulario de usuario: nombre, edad y email. Con Zod, esto se puede hacer así:

const UserSchema = z.object({
name: z.string(),
age: z.number().int().nonnegative(),
email: z.string().email()
});

Este esquema define tres propiedades con sus respectivos tipos. Además, usamos .int() y .nonnegative() para asegurarnos de que la edad sea un número entero no negativo.

Para validar datos con este esquema:

const result = UserSchema.safeParse({
name: 'Michael',
age: 28,
});
if (result.success) {
console.log('Datos válidos:', result.data);
} else {
console.error('Errores de validación:', result.error.issues);
}

El método safeParse devuelve un objeto que nos dice si los datos pasaron la validación. En caso de que no, nos da detalles precisos de qué salió mal.

Derivando tipos automáticamente

Un punto fuerte de Zod es que podemos derivar un tipo TypeScript directamente desde el esquema:

type User = z.infer<typeof UserSchema>;

De esta manera, si usamos la variable User en otras partes del código, siempre estará sincronizada con el esquema. Si cambiamos el esquema, el tipo cambia también.

Sirve parar evitar problemas donde los tipos y validadores se desincronizan, algo que puede pasar fácilmente si usamos otras librerías de validación.

Validación de arrays y esquemas anidados

Si necesitamos validar una lista de usuarios, simplemente usamos:

const UsersSchema = z.array(UserSchema);

También podemos tener objetos más complejos, con propiedades que son a su vez otros esquemas:

const GroupSchema = z.object({
groupName: z.string(),
members: z.array(UserSchema)
});

Esto nos permite construir validaciones a medida, sin repetir código y con la tranquilidad de que todo está bien tipado.

Casos de uso típicos

Zod es útil en varios contextos:

  • Validar datos que vienen del backend (REST, GraphQL, etc.)
  • Validar configuraciones o archivos JSON antes de procesarlos
  • Validar inputs en formularios (especialmente con React)
  • Validar variables de entorno en tiempo de arranque

Para este último punto, incluso existe una utilidad llamada zod-env que se integra fácilmente.

¿Por qué usar Zod y no otra librería?

Existen otras opciones, como Joi o Yup. Sin embargo, Zod tiene algunas características que lo hacen atractivo si trabajamos con TypeScript:

  • No requiere definiciones de tipo separadas.
  • Es pequeño y no tiene dependencias.
  • Está enfocado en TypeScript desde el inicio.

Además, su API es bastante intuitiva y no requiere mucho esfuerzo para aprenderla.

Conclusión

Zod nos permite validar datos sin sacrificar la seguridad que nos ofrece TypeScript. Al eliminar la duplicación entre tipos y validadores, simplificamos el código y reducimos errores. No es una solución mágica, pero en muchos casos es todo lo que necesitamos para mantener nuestros datos bajo control.

Vale la pena probarlo y ver si se ajusta a nuestras necesidades. Al final, cada proyecto es distinto, pero contar con herramientas que se integran bien con TypeScript nos puede ahorrar bastante tiempo.