Skip to content

Lección 89 — Introducción a Genéricos

Los genéricos permiten crear componentes (funciones, clases, interfaces, types) que funcionan con múltiples tipos sin perder la seguridad de tipos. Son la herramienta más poderosa de TypeScript para escribir código reutilizable.

Sin genéricos, una función identity tendría que usar any (perdiendo información de tipo) o escribir una versión por cada tipo:

// Con any — pierde el tipo
function identity(arg: any): any {
return arg;
}
// Con genérico — preserva el tipo
function identity<T>(arg: T): T {
return arg;
}
const resultado = identity<string>('Hola'); // tipo: string
const numero = identity(42); // tipo: 42 (inferido)
// Parámetro de tipo <T>
function primera<T>(arr: T[]): T | undefined {
return arr[0];
}
// Tipo inferido automáticamente
const primero = primera([1, 2, 3]); // tipo: number | undefined
const primeroStr = primera(['a', 'b']); // tipo: string | undefined
function par<A, B>(a: A, b: B): [A, B] {
return [a, b];
}
const resultado = par('edad', 30); // tipo: [string, number]
interface Caja<T> {
contenido: T;
abrir(): T;
}
type Resultado<T> = {
exito: boolean;
datos: T;
error?: string;
};
let numeros: Array<number> = [1, 2, 3];
let nombres: Array<string> = ['Ana', 'Luis'];
// Equivalente a:
let numeros2: number[] = [1, 2, 3];
// Función genérica para el primer elemento
function primero<T>(arr: T[]): T | undefined {
return arr.length > 0 ? arr[0] : undefined;
}
console.log(primero([1, 2, 3])); // tipo: number | undefined
console.log(primero(['a', 'b', 'c'])); // tipo: string | undefined
// Función genérica para invertir un par
function invertirPar<A, B>(par: [A, B]): [B, A] {
return [par[1], par[0]];
}
const invertido = invertirPar(['Ana', 30]); // tipo: [number, string]
// Interfaz genérica
interface Repositorio<T> {
obtener(id: number): T;
guardar(item: T): void;
eliminar(id: number): void;
}
class UsuarioRepositorio implements Repositorio<{ id: number; nombre: string }> {
private items: { id: number; nombre: string }[] = [];
obtener(id: number) {
return this.items.find(i => i.id === id)!;
}
guardar(item: { id: number; nombre: string }) {
this.items.push(item);
}
eliminar(id: number) {
this.items = this.items.filter(i => i.id !== id);
}
}
// Type genérico
type ParClaveValor<K, V> = {
clave: K;
valor: V;
};
const entrada: ParClaveValor<string, number> = {
clave: 'edad',
valor: 30
};

Escribe una función genérica mezclar<T, U>(a: T, b: U): T & U que combine dos objetos en uno solo (usa spread operator). Pruébala con:

  • Un objeto { nombre: string } y otro { edad: number }.
  • Un objeto { id: number } y otro { activo: boolean }.

Verifica que el resultado tenga todas las propiedades.

La convención es usar letras mayúsculas para los parámetros de tipo: T, U, V, K (key), V (value), E (element). Pero puedes usar nombres descriptivos: ResponseType, ItemType.

TS puede inferir el tipo genérico automáticamente en la mayoría de los casos. No necesitas escribir identity<string>('Hola'); basta con identity('Hola'). Especifica el tipo explícitamente solo cuando la inferencia no sea suficiente.