Lección 15 de 20 · Lectura y práctica
Mini-Proyecto: Desarrollar una Librería de Validación Tipada
Tipo de lección: VideoConcepto claveEn arquitecturas complejas, la validación de datos es una capa crítica que garantiza la integridad del sistema. Una librería de validación tipada en TypeScript va más allá de simples.
Del concepto a la práctica
Taller de esta lección
Una librería de validación puede combinar predicados que reciben unknown y producen type guards. Así la comprobación de ejecución y el estrechamiento estático permanecen alineados.
Ejemplo resuelto
type Guard<T> = (x: unknown) => x is T;
const isString: Guard<string> = x => typeof x === "string";
function validate<T>(x: unknown, guard: Guard<T>): T | undefined { return guard(x) ? x : undefined; }
console.log(validate("ok", isString)); // ok
console.log(validate(7, isString)); // undefinedPruébalo
Crea
isPositivepara números mayores que cero.Valida
3y-1.Usa el valor devuelto solo si no es
undefined.Añade una comprobación de objeto con
idtextual.
Comprueba tu resultado
Los resultados deben ser 3 y undefined; el objeto con id válida debe aceptarse.
Error frecuente: devolver boolean y luego asumir que el dato cambió de tipo. Corrígelo declarando x is T; el predicado comunica al compilador qué queda demostrado.
Un predicado escrito incorrectamente puede mentir al compilador: la firma x is T no demuestra que su cuerpo sea correcto. Para isPositive usa typeof x==="number" junto con Number.isFinite(x) y x>0, y prueba NaN,Infinity,0,-1,3. El resultado undefined funciona para este validador de strings/números; si permites undefined como valor válido, usa un Result discriminado para separar éxito de ausencia. Añade pruebas negativas por cada guard antes de publicarlo como librería.

Mapa de prácticaUna condición decide qué camino ejecuta el programa. Un bucle repite una operación mientras queden elementos, y termina cuando la lista se agota. Separar ambas ideas ayuda a seguir el flujo y comprobar casos límite.
Ver la infografía en tamaño completo ↗Fuentes para profundizar
Tipo de lección: Video
Concepto clave
En arquitecturas complejas, la validación de datos es una capa crítica que garantiza la integridad del sistema. Una librería de validación tipada en TypeScript va más allá de simples comprobaciones: utiliza tipos genéricos para inferir la estructura de los datos validados, creando un flujo de tipos seguro desde la entrada hasta el uso interno. Imagina un control de aduanas digital: no solo revisa pasaportes (validación), sino que también actualiza automáticamente los permisos del viajero (tipado) en el sistema.
El núcleo de este patrón es la composición de validadores. En lugar de funciones aisladas, construyes validadores reutilizables que se combinan como piezas de Lego, donde cada pieza aporta su lógica de validación y su contrato de tipos. Esto permite crear esquemas complejos para objetos anidados, arrays condicionales o uniones discriminadas, manteniendo el tipado preciso en cada paso.
"La magia no está en validar, sino en que TypeScript sepa exactamente qué forma tiene el dato después de pasar la validación."
Cómo funciona en la práctica
Vamos a construir la base de nuestra librería. Empezamos definiendo un tipo genérico para un validador:
type Validator = (input: unknown) => input is T; Este tipo dice: "dame algo desconocido y te digo si es de tipo T". Pero queremos más: queremos transformar. Creamos un validador que también refine el tipo:
function string(): Validator {
return (input: unknown): input is string => typeof input === 'string';
} Ahora, la clave: combinadores. Un combinador toma validadores y devuelve uno nuevo:
function object<T extends Record<string, Validator<any>>>(schema: T): Validator<{ [K in keyof T]: InferType<T[K]> }> {
return (input: unknown): input is any => {
if (typeof input !== 'object' || input === null) return false;
for (const key in schema) {
if (!schema[key](input[key])) return false;
}
return true;
};
}Nota cómo InferType (que definiremos) extrae el tipo del validador. Si usamos object({ name: string(), age: number() }), TypeScript inferirá que el resultado es { name: string, age: number }.
Caso de estudio
Implementemos un validador para un formulario de usuario en una aplicación empresarial. Necesitamos validar:
- Nombre: string, mínimo 2 caracteres
- Email: string con formato de email
- Edad: number opcional entre 18 y 100
- Roles: array de strings, al menos uno seleccionado
Primero, creamos validadores básicos con tipos:
const minLength = (length: number): Validator =>
(input): input is string => typeof input === 'string' && input.length >= length;
const email = (): Validator =>
(input): input is string => typeof input === 'string' && /^[^@]+@[^@]+\.[^@]+$/.test(input);
const optional = (validator: Validator): Validator =>
(input): input is T | undefined => input === undefined || validator(input); Ahora, componemos el esquema completo:
const userSchema = object({
name: compose(string(), minLength(2)),
email: compose(string(), email()),
age: optional(compose(number(), (n): n is number => n >= 18 && n <= 100)),
roles: array(string())
});Al validar const data = { name: "Ana", email: "ana@empresa.com", roles: ["admin"] };, si pasa, TypeScript sabe que data es { name: string, email: string, age?: number, roles: string[] } con age opcional.
Errores comunes
- No inferir tipos correctamente en combinadores: Si tu función
objectdevuelveValidator<any>, pierdes todo el tipado. Usa tipos genéricos anidados yinferpara extraer tipos de validadores. - Validar en tiempo de ejecución pero no en compilación: Asegúrate de que los esquemas sean tipos, no solo valores. Por ejemplo,
schema: Record<string, Validator<any>>permite cualquier validador, peroT extends Record<string, Validator<any>>conserva las claves. - Olvidar casos límite: ¿Qué pasa con
null,undefinedo arrays vacíos? Define políticas claras (ej.,optionalpara opcionales) y documenta el comportamiento. - No proporcionar mensajes de error útiles: En nivel avanzado, agrega un sistema de errores tipado que capture qué validador falló y por qué, sin romper la inferencia de tipos.
- Abusar de
asen implementaciones: Evita afirmaciones de tipo (as) dentro de validadores; usa guardias de tipo (input is T) para mantener la seguridad.
Checklist de dominio
- Puedo crear un validador genérico que infiera el tipo de salida correctamente.
- Sé implementar combinadores como
object,array,unionque preserven el tipado. - He construido un esquema para un objeto anidado de 3 niveles con validaciones condicionales.
- Puedo explicar la diferencia entre
Validator<T>y una función que devuelveboolean. - He integrado mensajes de error tipados en mi librería sin perder inferencia.
- Sé cómo testear validadores tanto en tipo como en ejecución.
- Puedo optimizar la librería para evitar checks redundantes en objetos grandes.
Implementa una librería de validación tipada para esquemas de API REST
En este ejercicio, construirás una librería de validación que pueda manejar respuestas de API REST típicas, con tipos seguros. Sigue estos pasos:
- Define los tipos base: Crea un tipo
Validatorque sea una guardia de tipo. ImplementaInferTypeque extraiga el tipoUdeValidator. - Implementa validadores primitivos: Escribe funciones para
string(),number(),boolean(), yliteral(value)(ej.,literal('success')). Asegúrate de que devuelvanValidator. - Crea combinadores: Implementa
object(schema)para objetos,array(validator)para arrays, yoptional(validator)para campos opcionales. Usa genéricos para inferir los tipos resultantes. - Añade validaciones complejas: Agrega
union(validators)para uniones (ej.,string | number) yintersection(validators)para intersecciones. Prueba con un esquema que incluya ambos. - Construye un esquema real: Valida una respuesta de API como
{ status: 'ok', data: { users: Array<{ id: number, name: string }> }, error?: string }. Escribe tests en TypeScript que verifiquen el tipado y la validación.
Entrega el código en un repositorio o archivo, con comentarios que expliquen las decisiones de diseño.
Pistas
- Usa tipos condicionales como `T extends Validator
? U : never` para InferType. - En `object`, itera sobre las claves del esquema con un bucle `for...in` y aplica cada validador.
- Para `union`, prueba cada validador en orden hasta que uno tenga éxito; asegura que el tipo inferido sea la unión de los tipos.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.
Sigue con TypeScript Avanzado: Patrones Genéricos y Tipado Profundo para Arquitecturas Complejas
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.