Cuándo usar Zod en lugar de TypeScript para validación en runtime

zod-vs-typescript-validacion-runtime

Zod vs TypeScript puro: cuándo usar validación en runtime

¿Confías en TypeScript para proteger tu app en producción? Deja de hacerlo. TypeScript es un analizador estático; su trabajo termina cuando el código se compila. Si quieres seguridad real en ejecución necesitas otra cosa. Aquí va la guía práctica: Zod vs TypeScript puro: cuándo usar validación en runtime.

TypeScript ordena tu código. Zod protege tus fronteras. Úsalos juntos, no en guerra.

Tiempo estimado de lectura: 4 min

  • TypeScript es un analizador estático: no protege en runtime.
  • Zod parsea en runtime y mantiene una sola fuente de verdad con z.infer.
  • Valida en las fronteras (endpoints, webhooks, env, uploads); confía en TypeScript dentro del dominio.
  • Mide impacto de rendimiento y evita validaciones redundantes en el core.

¿Confías en TypeScript para proteger tu app en producción? Deja de hacerlo. TypeScript es un analizador estático; su trabajo termina cuando el código se compila. Si quieres seguridad real en ejecución necesitas otra cosa. Aquí va la guía práctica: Zod vs TypeScript puro: cuándo usar validación en runtime.

Resumen rápido (lectores con prisa)

Qué es: Zod es una librería de validación y parsing en runtime; TypeScript es un sistema de tipos estático.

Cuándo usarlo: Usa Zod en las fronteras (endpoints, webhooks, env, uploads); usa TypeScript dentro del dominio.

Por qué importa: TypeScript sufre type erasure y no impide fallos en producción; Zod parsea y falla rápido.

Cómo usarlo: Definir esquemas Zod, derivar tipos con z.infer y parsear payloads en los handlers.

Por qué TypeScript no basta (y dónde duele más)

TypeScript tiene un problema estructural: Type Erasure. Los tipos desaparecen al compilar. Eso significa que las aserciones (as T) son mentiras que el compilador acepta y la app paga en runtime.

interface Usuario { id: number; email: string; }

const datos = await respuesta.json() as Usuario;
console.log(datos.email.toLowerCase()); // Boom si email no existe

Si la API cambia, o devuelve HTML en un error 500, tu código explota. TypeScript no está ahí para detenerlo.

Zod y el principio “Parse, don’t validate”

Zod opera en runtime. Su filosofía es clara: no intentes “validar” por inercia; parsea y falla rápido.

import { z } from 'zod';

const UsuarioSchema = z.object({
  id: z.number(),
  email: z.string().email(),
});

type Usuario = z.infer;

const res = await fetch(url);
const raw = await res.json();
const usuario = UsuarioSchema.parse(raw); // lanza si algo falla
console.log(usuario.email.toLowerCase());

Con z.infer mantienes una sola fuente de verdad: el esquema. Nada de duplicar interfaces y validadores.

safeParse vs parse

Si quieres manejo de errores controlado:

const result = UsuarioSchema.safeParse(raw);
if (!result.success) {
  // logging, métricas, respuesta 400 al cliente...
  throw new Error('Payload inválido');
}
const usuario = result.data;

safeParse devuelve un objeto con success y error para flujos menos crudos.

Dónde aplicar validación (regla práctica)

No todo necesita Zod. La regla del arquitecto es simple:

  • Valida en runtime en las fronteras: entrada HTTP, webhooks, archivos subidos, variables de entorno, LocalStorage.
  • Confía en TypeScript dentro del dominio: funciones internas, paso de props entre componentes, mutaciones internas en stores tipados.

Aplicar Zod en todas partes degrada rendimiento y readability. No validar en las fronteras te expone a fallos catastróficos.

Casos prácticos y patterns

1) Respuesta API (backend → frontend o backend → backend)

  • Parsea siempre antes de usar.
  • Registra el error y devuelve 400 o fallback claro.

2) Webhooks / n8n / automatizaciones

  • Parsea y verifica firma si aplica.
  • Rechaza rápido para evitar procesar datos corruptos.

3) Variables de entorno en arranque (ejemplo con Zod)

const EnvSchema = z.object({
  DATABASE_URL: z.string().url(),
  NODE_ENV: z.enum(['development','production']),
});
const env = EnvSchema.parse(process.env);

Arranque fallido = fallo visible y evitar estados inconsistentes.

4) Formularios en frontend

Integra Zod con React Hook Form para validar antes de mutar el estado o enviar al servidor.

Coste y alternativas: cuándo preocuparse por rendimiento

Zod añade CPU y peso al bundle. En la mayoría de apps esto es irrelevante frente a la estabilidad que gana tu producto. En sistemas de altísima demanda (millones de eventos por segundo) evalúa alternativas más ligeras o validaciones a medida.

Alternativas emergentes existen, pero la elección debe basarse en mediciones. No te cases con una librería sin perf tests en tu caso real.

Integración práctica: patrón recomendado

  1. Punto de entrada (API handler, webhook) → Zod parse
  2. Convertir a tipos con z.infer → pasar al core tipado con TypeScript
  3. Lógica interna → TypeScript puro, sin comprobaciones redundantes
  4. En el cliente, validar inputs críticos; en el servidor, validar todo lo externo

Conclusión y pasos accionables

  • Zod y TypeScript no son excluyentes. TypeScript organiza tu código; Zod lo hace seguro en producción.
  • Si tienes que elegir hoy, empieza por defender las fronteras: añade validación Zod en endpoints y webhooks.
  • Usa z.infer para que el tipo estático derive del esquema y mide impacto.

Recuerda: el compilador no vive en producción. Tú sí. Protege lo que importa.

Prueba esto ahora: añade un esquema Zod a uno de tus endpoints y corre safeParse con un payload inesperado. Verás la diferencia. Esto no acaba aquí; la próxima nota tratará cómo estructurar esquemas Zod para versiones y migraciones sin romper consumidores.

FAQ

¿TypeScript protege mi app en producción?

No. TypeScript es un analizador estático y sus tipos desaparecen al compilar (type erasure). No impide que datos inválidos lleguen a runtime.

¿Qué es Zod y por qué usarlo?

Zod es una librería de validación y parsing en runtime. Su filosofía es “parse, don’t validate”: parsea datos y falla rápido si no coinciden con el esquema, evitando errores silenciosos en producción.

¿Cuándo usar parse vs safeParse?

Usa parse cuando quieras que el proceso lance inmediatamente y falle rápido. Usa safeParse para manejar errores de forma controlada (logging, métricas, respuesta 400) sin exceptions no controladas.

¿Dónde aplicar validación en mi arquitectura?

Valida en las fronteras: endpoints HTTP, webhooks (p. ej. n8n), archivos subidos, variables de entorno, y LocalStorage. Dentro del dominio confía en TypeScript y evita validaciones redundantes.

¿Zod impacta tanto el rendimiento?

Zod añade CPU y peso al bundle, pero en la mayoría de apps el coste es aceptable frente a la estabilidad que aporta. En sistemas de altísima demanda evalúa alternativas más ligeras y mide con perf tests.

¿Cómo integrar Zod con TypeScript sin duplicar tipos?

Define esquemas Zod y deriva los tipos estáticos con z.infer. Así mantienes una sola fuente de verdad: el esquema.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *