Validación de datos en TypeScript: revisión de herramientas y prácticas
En el desarrollo web moderno con TypeScript, una de las tareas clave es garantizar la integridad de los datos. Incluso con la estricta tipificación estática de TypeScript, no se puede garantizar que los datos provenientes del mundo exterior (API, formularios, localStorage) coincidan con el formato esperado. Aquí es donde la validación en tiempo de ejecución (runtime validation) resulta útil: la verificación de datos durante la ejecución del programa. En este artículo, revisaremos tres bibliotecas populares: Zod, Yup y Joi, compararemos sus enfoques y mostraremos cómo integrar la validación en un proyecto TypeScript.
¿Por qué no son suficientes los tipos simples de TypeScript?
TypeScript verifica los tipos en tiempo de compilación, pero en tiempo de ejecución todas las anotaciones se borran. Esto significa que:
- Los datos del usuario pueden contener campos adicionales o faltar campos obligatorios
- Los números pueden llegar como cadenas de texto
- Los objetos pueden ser
nulloundefined
Las bibliotecas de validación resuelven este problema proporcionando esquemas que funcionan tanto como verificación como para la inferencia de tipos.
1. Zod — el estándar moderno
Zod es la biblioteca más popular para validación en TypeScript. Su principal ventaja es la inferencia automática de tipos TypeScript a partir de los esquemas.
Instalación
npm install zodEjemplo de esquema básico
import { z } from 'zod';
const UserSchema = z.object({ id: z.number().positive(), name: z.string().min(2).max(50), email: z.string().email(), age: z.number().int().min(18).optional(),});
// Inferencia de tipo: { id: number; name: string; email: string; age?: number }type User = z.infer<typeof UserSchema>;
// Validaciónconst result = UserSchema.safeParse(inputData);if (!result.success) { console.error(result.error.errors);} else { // result.data — datos correctos con tipo User processUser(result.data);}Funcionalidades avanzadas
- Transformación:
z.string().transform(val => val.trim()) - Uniones discriminadas:
z.discriminatedUnion('type', [...]) - Esquemas recursivos:
z.lazy(() => NodeSchema) - Errores personalizados:
z.string().refine(val => !val.includes('bad'), 'No se puede usar la palabra bad')
2. Yup — una herramienta probada por el tiempo
Yup es una biblioteca con una larga trayectoria, creada originalmente para la validación de formularios. Se integra excelentemente con Formik y React Hook Form.
Instalación
npm install yupEjemplo de esquema
import * as yup from 'yup';
const productSchema = yup.object({ title: yup.string().required('El nombre es obligatorio').min(3), price: yup.number().positive('El precio debe ser positivo').required(), inStock: yup.boolean().default(true),});
type Product = yup.InferType<typeof productSchema>;
// ValidaciónproductSchema.validate(inputData, { abortEarly: false }) .then(validData => console.log(validData)) .catch(err => console.error(err.errors));Características de Yup
- Soporte para validación condicional:
.when('field', ...) - Mensajes de error integrados en español (al configurar la locale)
- Trabajo sencillo con objetos anidados y arrays
- Métodos
cast()ytransform()para conversión de tipos
3. Joi — potente, pero más pesado
Joi es una biblioteca legendaria del ecosistema Node.js (Hapi.js). Proporciona la máxima flexibilidad, pero no tiene integración nativa con TypeScript (requiere definición manual de tipos).
Instalación
npm install joi @types/joi<