# Validación en Tiempo de Ejecución de Respuestas de API: Por Qué TypeScript No Basta
TypeScript solo verifica tipos en tiempo de compilación. Los datos de las API llegan en tiempo de ejecución sin garantía de que coincidan con tus interfaces. Sin validación extra, los desajustes aparecen como errores visibles para el usuario: campos indefinidos, tipos incorrectos, objetos faltantes.
Problemas Sin Comprobaciones en Tiempo de Ejecución
Las interfaces de TypeScript dan una falsa sensación de seguridad. Aquí un código típico sin validación:
interface User {
id: number;
name: string;
email: string;
}
const getUser = async (): Promise<User> => {
const res = await fetch('/api/user');
return res.json(); // Sin verificar los datos reales
};
TypeScript confía en la anotación de tipo e ignora la respuesta real del servidor. Riesgos clave:
- Cambios en la estructura del backend:
full_name→fullNamegeneraundefined. - Desajustes de tipos: cadena
"123"en vez de número123provoca concatenación en lugar de suma. - Campos condicionales:
addressausente en casos límite, error al acceder auser.address.city. - API de terceros con documentación desactualizada.
Librerías de Validación de Esquemas
¿La solución? Librerías de validación de esquemas en tiempo de ejecución. Analizan datos reales y lanzan errores ante desajustes. Las mejores opciones para TypeScript:
- Zod: Infiera tipos desde esquemas, ecosistema enorme.
- Yup: Ideal con Formik.
- Valibot: Amigable con bundles, tree-shakable.
- Joi: Raíces en Node.js, enfocado en backend.
- ArkType: Prioridad en rendimiento.
Implementación con Zod
Zod une esquema, tipos y validación en uno. Ejemplo con usuario:
import { z } from 'zod';
const UserSchema = z.object({
id: z.number(),
name: z.string(),
email: z.string().email(),
});
type User = z.infer<typeof UserSchema>;
const getUser = async (): Promise<User> => {
const res = await fetch('/api/user');
const data = await res.json();
return UserSchema.parse(data); // Error ante desajuste
};
parse() lanza un ZodError con detalles del fallo. Usa safeParse() para un objeto con success y error.
Escalado en Proyectos Reales
Para apps grandes, centraliza esquemas para todos los endpoints. Envuelve fetch así:
const apiFetch = async <T>(url: string, schema: z.ZodSchema<T>): Promise<T> => {
const res = await fetch(url);
const data = await res.json();
return schema.parse(data);
};
const users = await apiFetch('/api/users', z.array(UserSchema));
Manejo de errores: Registra en Sentry, muestra mensajes amigables al usuario. Para arrays, valida cada ítem.
- Usa
z.array(UserSchema)para listas. z.union()para respuestas polimórficas.z.lazy()para estructuras recursivas.z.transform()para normalizar datos.
Lecciones Clave
- TypeScript no garantiza tipos en tiempo de ejecución para datos externos: API, localStorage, params de URL.
- La validación de esquemas detecta desajustes pronto, reduce tiempo de depuración.
- Zod es el estándar frontend: tipos desde esquemas, integración sencilla.
- En equipos con backends separados, evita fallos silenciosos.
- Escala con wrappers de fetch para consistencia.
La validación en tiempo de ejecución cubre el hueco entre las comprobaciones de compilación de TypeScript y la ejecución. En producción, reduce drásticamente bugs por contratos de API desincronizados.
— Editorial Team
Aún no hay comentarios.