Volver a TypeScript Intermedio

Tipos Avanzados en TypeScript

El sistema de tipos de TypeScript es Turing-completo. Estas características avanzadas permiten modelar relaciones de datos complejas con precisión.

Tipos Mapeados

Transforma cada propiedad de un tipo:

type SoloLectura<T> = { readonly [K in keyof T]: T[K]; }; type Opcional<T> = { [K in keyof T]?: T[K]; }; type Anulable<T> = { [K in keyof T]: T[K] | null; }; // Personalizado: hacer campos específicos requeridos type CamposRequeridos<T, K extends keyof T> = T & Required<Pick<T, K>>; interface Usuario { id?: number; nombre?: string; correo?: string; } type UsuarioConId = CamposRequeridos<Usuario, 'id'>; // id requerido, resto opcional

Tipos Condicionales

Tipos que dependen de una condición:

type EsArray<T> = T extends any[] ? true : false; // EsArray<string[]> = true // EsArray<string> = false // Extraer el tipo del elemento de un array type TipoElemento<T> = T extends (infer E)[] ? E : never; type E = TipoElemento<string[]>; // string // Desenvolver una Promise type Esperado<T> = T extends Promise<infer R> ? Esperado<R> : T; type A = Esperado<Promise<Promise<string>>>; // string // Práctico: obtener tipo de retorno sin undefined type SinUndefined<T> = T extends undefined ? never : T;

Tipos Literales de Plantilla

Compone tipos de cadena como template literals:

type NombreEvento = 'click' | 'focus' | 'blur'; type Manejador = `on${Capitalize<NombreEvento>}`; // 'onClick' | 'onFocus' | 'onBlur' type PropiedadCSS = 'margin' | 'padding'; type DireccionCSS = 'top' | 'right' | 'bottom' | 'left'; type ClasesCSS = `${PropiedadCSS}-${DireccionCSS}`; // 'margin-top' | 'margin-right' | ... | 'padding-left' // Claves de eventos tipadas type MapaEventos = { 'usuario:login': { idUsuario: string }; 'usuario:logout': void; 'producto:agregado': { idProducto: string; cantidad: number }; }; type ClaveEvento = keyof MapaEventos; // 'usuario:login' | 'usuario:logout' | 'producto:agregado'

Uniones Discriminadas

type Resultado<T, E = Error> = | { ok: true; valor: T } | { ok: false; error: E }; async function obtenerUsuario(id: string): Promise<Resultado<Usuario>> { try { const usuario = await db.usuario.findUnique({ where: { id } }); if (!usuario) return { ok: false, error: new Error('No encontrado') }; return { ok: true, valor: usuario }; } catch (e) { return { ok: false, error: e as Error }; } } const resultado = await obtenerUsuario('123'); if (resultado.ok) { console.log(resultado.valor.nombre); // TypeScript sabe que valor existe } else { console.error(resultado.error.message); // TypeScript sabe que error existe }

La Palabra Clave infer

Extrae tipos de otros tipos:

// Extraer tipos de parámetros de función type Parametros<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never; // Extraer tipo de retorno type TipoRetorno<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : never; // Extraer tipo de resolución de Promise type ValorPromesa<T> = T extends Promise<infer V> ? ValorPromesa<V> : T; function saludar(nombre: string, edad: number) { return `Hola ${nombre}`; } type ParamsSaludar = Parametros<typeof saludar>; // [string, number] type RetornoSaludar = TipoRetorno<typeof saludar>; // string