Genéricos en funciones

Las funciones también pueden especificar genéricos, de tal manera que el tipo de datos de uno de los parámetros de la función es desconocido hasta el momento en el que se invoca la función y se especifica el valor de ese parámetro. Esto tendrá una serie de consecuencias interesantes en la forma en la que accedemos a esa variable.

Cuando trabajamos con TypeScript, los genéricos nos ofrecen una herramienta poderosa para crear funciones flexibles y seguras que pueden manejar distintos tipos de datos sin perder la tipificación. En particular, cuando diseñamos funciones, los genéricos nos permiten parametrizar el tipo de los argumentos y el tipo de retorno, lo que resulta especialmente útil en escenarios donde manejamos múltiples variantes de un mismo concepto.

Imaginemos que estamos desarrollando una API para una red social que permite distintos tipos de publicaciones. Por ejemplo, tenemos una publicación simple que es una nota con un mensaje de texto, otra que es una nota colorida que incluye un color y la posibilidad de subir fotos, y también publicaciones de vídeo que, además de una URL, incluyen la duración en segundos. Nuestra API tiene un único endpoint para subir cualquier tipo de publicación mediante un método HTTP POST.

Una forma inicial de abordar esto sería definir un tipo unión que englobe todas las variantes de publicación, y hacer que la función que sube la publicación acepte ese tipo. Sin embargo, esto implica que dentro de la función tendremos que hacer comprobaciones para saber qué tipo de publicación estamos manejando y actuar en consecuencia. Otra opción menos recomendable sería aceptar un tipo any, pero esto pierde toda la seguridad de tipos y puede llevar a errores al pasar datos no válidos.

Aquí es donde los genéricos en funciones nos ofrecen una solución elegante. Podemos parametrizar la función que sube la publicación con un tipo genérico Publicacion, de modo que la función acepte un argumento de ese tipo y también devuelva un valor del mismo tipo. Esto nos permite mantener la flexibilidad para manejar cualquier tipo de publicación, pero con la seguridad de que el tipo se mantiene consistente.

El código para esta función genérica podría ser algo así:

function subir<Publicacion>(p: Publicacion): Publicacion {
  return p;
}

Cuando llamamos a esta función, podemos dejar que TypeScript infiera el tipo automáticamente a partir del argumento que le pasamos. Por ejemplo, si tenemos un objeto nota con un mensaje, al llamar a subir(nota), TypeScript entiende que el tipo genérico Publicacion es el tipo de nota, y por tanto el valor devuelto también será de ese tipo.

type Nota = {
  mensaje: string;
};

const nota: Nota = { mensaje: "Hola, mundo" };

const resultado = subir(nota);
// TypeScript infiere que resultado es de tipo Nota

Esto nos evita tener que especificar explícitamente el tipo genérico al llamar a la función, haciendo el código más limpio y aprovechando la inferencia de tipos que ofrece TypeScript.

Además, podemos extender esta idea para que la función acepte múltiples parámetros genéricos si fuera necesario, por ejemplo, subir<Publicacion, Extra>(p: Publicacion, extra: Extra), lo que nos da aún más flexibilidad para manejar distintos tipos de datos relacionados.

Sin embargo, hay que tener en cuenta que esta flexibilidad también puede ser un arma de doble filo. Si no restringimos el tipo genérico, cualquiera podría pasar un valor que no tenga sentido para nuestra API, como un número o un string simple, y aunque TypeScript lo acepte, la API probablemente rechazaría ese dato. Por eso, en escenarios reales, conviene combinar los genéricos con restricciones que limiten los tipos permitidos, asegurando que solo se puedan subir publicaciones válidas.

En definitiva, los genéricos en funciones nos permiten crear APIs más robustas y reutilizables, manteniendo la seguridad de tipos y facilitando la gestión de múltiples variantes de datos sin duplicar código ni perder claridad.

Lista de reproducción
  1. 1
    Temporada 1
    5 minutos
  2. 2
    ¿Qué es TypeScript?
    11 minutos
  3. 3
    Instalando TypeScript
    8 minutos
  4. 4
    Compilando un Hola Mundo sencillo
    7 minutos
  5. 5
    Hola Mundo pero con tipos
    10 minutos
  6. 6
    Tipos: tipos primitivos
    12 minutos
  7. 7
    Tipos: tipos especiales (any, null, ...)
    10 minutos
  8. 8
    Tipos: arrays y tuplas
    11 minutos
  9. 9
    Tipos: objetos
    7 minutos
  10. 10
    Funciones: lo básico
    9 minutos
  11. 11
    Funciones: tipando funciones
    9 minutos
  12. 12
    Clases: introducción a las clases
    9 minutos
  13. 13
    Clases: creando una clase
    10 minutos
  14. 14
    Clases: modificador private
    8 minutos
  15. 15
    Clases: modificador readonly
    3 minutos
  16. 16
    Clases: Atributos virtuales con getters y setters
    10 minutos
  17. 17
    Clases: herencia
    9 minutos
  18. 18
    Clases: modificadores abstract y protected
    8 minutos
  19. 19
    Tipos alias
    6 minutos
  20. 20
    Tipos literales
    5 minutos
  21. 21
    Uniones de tipos
    7 minutos
  22. 22
    Uniones discriminantes
    7 minutos
  23. 23
    Intersecciones de tipos
    5 minutos
  24. 24
    Interfaces: introducción
    7 minutos
  25. 25
    Interfaces: modificadores y funciones
    9 minutos
  26. 26
    Interfaces: usándolas con clases
    8 minutos
  27. 27
    Interfaces: herencia de interfaces
    8 minutos
  28. 28
    Interfaces: interfaces indizadas
    5 minutos
  29. 29
    Interfaces: funciones y tipos híbridos
    5 minutos
  30. 30
    ¿Qué diferencia hay entre interfaces y tipos? (2020)
    8 minutos
  31. 31
    Casteos con as
    6 minutos
  32. 32
    instanceof y las guardas
    9 minutos
  33. 33
    Tipos enumerados
    8 minutos
  34. 34
    Valores avanzados para enumerados
    7 minutos
  35. 35
    Enumerados con valores computados
    6 minutos
  36. 36
    Genéricos en tipos
    8 minutos
  37. 37
    Múltiples genéricos y buenas prácticas
    5 minutos
  38. 38
    Genéricos en funciones
    8 minutos
  39. 39
    Genéricos con restricciones
    6 minutos
  40. 40
    Tipos de utilidad
    3 minutos
  41. 41
    Exportando módulos
    9 minutos
  42. 42
    Importando módulos
    7 minutos
  43. 43
    Export default e import asterisco
    6 minutos
  44. 44
    tsconfig
    7 minutos
  45. 45
    Módulos desde NPM
    7 minutos
  46. 46
    Arroba types y los .d.ts
    8 minutos
  47. 47
    Ejemplo (1): creando una API REST simple en TypeScript
    11 minutos
  48. 48
    Ejemplo (2): montando un servidor Express
    8 minutos
  49. 49
    Ejemplo (3): haciendo las funciones de control de datos
    11 minutos
  50. 50
    Ejemplo (4): conectando todas las piezas
    7 minutos