Saltar al contenidoPedro Farbo
Lección 5 / 525 min

Introducción a los Genéricos

Introducción a los Genéricos

Los genéricos permiten crear componentes que funcionan con varios tipos mientras mantienen la seguridad de tipos. Son como "plantillas" que puedes personalizar.

El Problema

Imagina que quieres crear una función que retorna el primer elemento de un array:

typescript
// Sin genéricos - pierde información de tipofunction primerElemento(arr: any[]): any {  return arr[0];} const num = primerElemento([1, 2, 3]);    // tipo: anyconst str = primerElemento(["a", "b"]);   // tipo: any // ¡Perdimos la información de que num es number y str es string!

La Solución: Genéricos

typescript
function primerElemento<T>(arr: T[]): T {  return arr[0];} const num = primerElemento([1, 2, 3]);    // tipo: numberconst str = primerElemento(["a", "b"]);   // tipo: string // ¡TypeScript infiere el tipo correctamente!

La T es un parámetro de tipo - un placeholder que será reemplazado por el tipo real cuando se llame a la función.

Sintaxis Básica

typescript
// Función genéricafunction identidad<T>(valor: T): T {  return valor;} // Llamando - TypeScript infiere el tipoidentidad("texto");  // T = stringidentidad(42);       // T = number // O especificando explícitamenteidentidad<boolean>(true);

Múltiples Parámetros de Tipo

typescript
function par<K, V>(clave: K, valor: V): [K, V] {  return [clave, valor];} const resultado = par("edad", 30); // [string, number]const otro = par(1, true);         // [number, boolean]

Interfaces Genéricas

typescript
interface Caja<T> {  contenido: T;} const cajaDeTexto: Caja<string> = {  contenido: "¡Hola!"}; const cajaDeNumero: Caja<number> = {  contenido: 42};

Clases Genéricas

typescript
class Pila<T> {  private items: T[] = [];   push(item: T): void {    this.items.push(item);  }   pop(): T | undefined {    return this.items.pop();  }   peek(): T | undefined {    return this.items[this.items.length - 1];  }} const pilaNumeros = new Pila<number>();pilaNumeros.push(1);pilaNumeros.push(2);console.log(pilaNumeros.pop()); // 2 const pilaStrings = new Pila<string>();pilaStrings.push("a");pilaStrings.push("b");

Restricciones (Constraints)

Limita qué tipos pueden usarse con extends:

typescript
// T debe tener la propiedad 'length'interface TieneLongitud {  length: number;} function obtenerLongitud<T extends TieneLongitud>(item: T): number {  return item.length;} obtenerLongitud("hello");     // OK - string tiene lengthobtenerLongitud([1, 2, 3]);   // OK - array tiene lengthobtenerLongitud({ length: 10 }); // OK - objeto tiene length obtenerLongitud(42);          // Error - number no tiene length

Usando Parámetros de Tipo en Restricciones

typescript
function obtenerPropiedad<T, K extends keyof T>(obj: T, clave: K): T[K] {  return obj[clave];} const persona = { nombre: "Pedro", edad: 30 }; obtenerPropiedad(persona, "nombre"); // OK, retorna stringobtenerPropiedad(persona, "edad");   // OK, retorna numberobtenerPropiedad(persona, "email");  // Error - 'email' no existe

Parámetros de Tipo por Defecto

typescript
interface Respuesta<T = any> {  data: T;  status: number;} // Usa tipo por defecto (any)const respuesta1: Respuesta = {  data: "cualquier cosa",  status: 200}; // Especifica el tipoconst respuesta2: Respuesta<Usuario> = {  data: { nombre: "Pedro", edad: 30 },  status: 200};

Ejemplo Práctico: Función de API

typescript
async function obtenerDatos<T>(url: string): Promise<T> {  const response = await fetch(url);  return response.json();} interface Usuario {  id: number;  nombre: string;} // TypeScript sabe el tipo de retornoconst usuario = await obtenerDatos<Usuario>("/api/usuario/1");console.log(usuario.nombre); // ¡El autocompletado funciona!

Conclusión

Los genéricos son una herramienta poderosa para crear código flexible y con seguridad de tipos. Con ellos, puedes escribir componentes reutilizables sin sacrificar los beneficios del tipado estático.

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e