Genéricos de TypeScript para Devs Reales
Dejá de copiar y pegar tipos. Una guía práctica de genéricos, tipos condicionales y tipos utilitarios que harán tu codebase 10 veces más mantenible.
El problema que resuelven los genéricos
Sin genéricos terminás con tres malas opciones: usar any (inseguro), copiar y pegar el tipo para cada variante (ruidoso), o escribir sobrecargas (verboso). Los genéricos te dan una cuarta opción: escribirlo una vez y dejar que quien llame especifique el tipo.
Funciones genéricas
El genérico más simple es una función que devuelve el mismo tipo que recibe. El <T> es un parámetro de tipo — pensalo como una variable, pero para tipos.
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
const n = first([1, 2, 3]); // inferido: number | undefined
const s = first(['a', 'b']); // inferido: string | undefinedRestricciones con extends
Podés restringir qué tipos están permitidos como T. Esto te permite acceder a propiedades en T que TypeScript puede garantizar que existen.
function getLabel<T extends { label: string }>(item: T): string {
return item.label; // seguro — T debe tener label
}Tipos condicionales
Los tipos condicionales te permiten expresar lógica if-else a nivel de tipos. Son la base de la mayoría de los tipos utilitarios avanzados en la librería estándar de TypeScript.
type EsString<T> = T extends string ? true : false;
type A = EsString<string>; // true
type B = EsString<number>; // falseTipos utilitarios que vale la pena conocer
- Partial<T> — hace todas las propiedades opcionales
- Required<T> — hace todas las propiedades requeridas
- Pick<T, K> — crea un tipo solo con las claves indicadas
- Omit<T, K> — crea un tipo sin las claves indicadas
- ReturnType<F> — extrae el tipo de retorno de una función
- Awaited<T> — desenvuelve un tipo Promise
Un codebase bien tipado no es uno donde toda variable tiene una anotación explícita. Es uno donde los tipos son precisos, acotados, y hacen trabajo real — detectando bugs antes de correr el código.