¿Qué son los Generics en JavaScript y para qué sirven?
\n\nImagina que escribes una función que debe funcionar con diferentes tipos de datos: números, cadenas, objetos. Sin Generics (genéricos) tendrías que duplicar el código o usar any, perdiendo el control sobre los tipos. Los Generics son un mecanismo que permite crear componentes (funciones, clases, interfaces) que funcionan con cualquier tipo de dato, pero manteniendo la información sobre el tipo.
Aunque JavaScript es un lenguaje de tipado dinámico, en el ecosistema Node.js se usa activamente TypeScript, que añade tipado estático. Es en TypeScript donde los genéricos se despliegan en todo su potencial. Sin embargo, entender sus principios es útil también para JavaScript puro, especialmente si escribes librerías o trabajas con frameworks modernos.
\n\nEn este artículo veremos:
\n- \n
- Para qué sirven los Generics \n
- Cómo declarar y usar genéricos en TypeScript \n
- Ejemplos para Node.js (API, procesamiento de datos) \n
- Limitaciones y mejores prácticas \n
Fundamentos de Generics: sintaxis y ejemplos básicos
\n\nPrimer genérico: la función identity
\n\nEl ejemplo clásico es una función que devuelve lo que recibe como entrada:
\n\n// Sin Generics\nfunction identity(value: any): any {\n return value;\n}\n\n// Con Generics\nfunction identity<T>(value: T): T {\n return value;\n}\n\n// Uso\nconst num = identity<number>(42); // num — number\nconst str = identity<string>('hola'); // str — string\n\n\nEl símbolo <T> es un parámetro de tipo. Puedes llamarlo como quieras (T, U, Item), pero la tradición dicta usar T (de Type).
Genéricos con múltiples parámetros
\n\nA veces es necesario trabajar con varios tipos simultáneamente:
\n\nfunction pair<T, U>(first: T, second: U): [T, U] {\n return [first, second];\n}\n\nconst result = pair<number, string>(1, 'uno');\n// result: [number, string]\n\n\nGenéricos en funciones flecha (Node.js)
\n\nEn React o utilidades se usan a menudo funciones flecha con genéricos:
\n\nconst wrapInArray = <T>(item: T): T[] => {\n return [item];\n};\n\nconst arr = wrapInArray('prueba'); // arr: string[]\n\n\nAplicación de Generics en proyectos reales de Node.js
\n\nManejadores de API con respuestas tipadas
\n\nImagina que escribes una función universal para peticiones a una API. Sin genéricos perderías los tipos de datos:
\n\n// Malo: any\nasync function fetchData(url: string): Promise<any> {\n const response = await fetch(url);\n return response.json();\n}\n\n// Bueno: Generics\nasync function fetchData<T>(url: string): Promise<T> {\n const response = await fetch(url);\n return response.json();\n}\n\n// Uso\ninterface User {\n id: number;\n name: string;\n}\n\nconst user = await fetchData<User>('/api/user/1');\nconsole.log(user.name); // TypeScript sabe que name es string\n\n\nColecciones de datos tipadas
\n\nAl trabajar con bases de datos (por ejemplo, con Prisma o Mongoose), los genéricos ayudan a crear repositorios universales:
\n\nclass Repository<T extends { id: number }> {\n private items: T[] = [];\n\n add(item: T): void {\n this.items.push(item);\n }\n\n getById(id: number): T | undefined {\n return this.items.find(item => item.id === id);\n }\n}\n\n// Uso\ninterface Product {\n id: number;\n title: string;\n price: number;\n}\n\nconst productRepo = new Repository<Product>();\nproductRepo.add({ id: 1, title: 'Laptop', price: 1000 });\nconst laptop = productRepo.getById(1);\n\n\nEnvoltorios para manejo de errores
\n\nFunción universal para