Enumerados con valores computados

No todos los lenguajes de programación tienen soporte para enumerados en los que el valor asignado a algunos o todos los miembros de la enumeración se compute dinámicamente en tiempo de ejecución, pero TypeScript sí. En este vídeo os cuento como aprovechar esta función, aunque no es una función que deberías usar demasiado.

Cuando queremos implementar un sistema de permisos, como el que podríamos encontrar en una red social o en plataformas como Discord, es común pensar en usar enumerados para representar cada permiso disponible. Por ejemplo, podríamos tener permisos para escribir mensajes, reaccionar, enviar enlaces o conectarse a canales de voz. En TypeScript, si no especificamos valores, los enumerados asignan automáticamente números secuenciales empezando desde cero. Sin embargo, en el contexto de permisos, asignar el valor cero a un permiso no tiene mucho sentido, porque cero suele representar la ausencia de permisos.

Para manejar esto de forma eficiente, podemos asignar valores que representen bits individuales, como 1, 2, 4, 8, y así sucesivamente. De esta manera, cada permiso corresponde a un bit distinto en un número, y podemos combinar permisos sumando esos valores. Por ejemplo, si un usuario tiene permisos con valor 6, eso significa que tiene los permisos correspondientes a 2 y 4, es decir, puede reaccionar y enviar enlaces. Este sistema de máscaras de bits es muy potente y eficiente, y es común en la gestión interna de permisos en sistemas informáticos.

Pero asignar manualmente estos valores puede ser tedioso y propenso a errores. Aquí es donde entran en juego los enumerados con valores computados en TypeScript. En lugar de escribir explícitamente cada valor, podemos definir que cada permiso sea el doble del anterior, usando expresiones que multipliquen por 2 el valor del permiso previo. Por ejemplo, podemos definir que el permiso de reaccionar sea el doble del permiso de escribir mensajes, el permiso de enviar enlaces sea el doble del permiso de reaccionar, y así sucesivamente.

Esto se traduce en un código como el siguiente:

enum Permisos {
  EscribirMensajes = 1,
  Reaccionar = EscribirMensajes * 2,
  EnviarEnlaces = Reaccionar * 2,
  ConectarseCanalesVoz = EnviarEnlaces * 2,
}

Gracias a esta técnica, TypeScript calcula automáticamente los valores numéricos correspondientes a cada permiso, que serían 1, 2, 4 y 8 respectivamente. Esto facilita la gestión y evita errores al asignar manualmente los valores.

Además, podemos usar constantes para inicializar estos valores, lo que nos da flexibilidad para cambiar el punto de partida sin modificar todo el enumerado. Por ejemplo, si definimos una constante inicial con valor 8, podemos usarla para que el primer permiso tenga ese valor y los siguientes se multipliquen por 2 sucesivamente:

const inicial = 8;

enum Permisos {
  EscribirMensajes = inicial,
  Reaccionar = EscribirMensajes * 2,
  EnviarEnlaces = Reaccionar * 2,
  ConectarseCanalesVoz = EnviarEnlaces * 2,
}

Esto hace que los valores sean 8, 16, 32 y 64 respectivamente.

Incluso es posible usar funciones para calcular los valores, aunque hay que tener cuidado con esto. Por ejemplo, asignar un valor aleatorio a un permiso es legal en TypeScript, pero puede no tener sentido práctico, ya que los permisos deberían ser constantes y predecibles para que el sistema funcione correctamente.

El objetivo principal de usar enumerados con valores computados es facilitar la programación, haciendo que sea sencillo reconocer y manejar cada permiso, mientras que internamente se usan valores numéricos que permiten operaciones eficientes, como combinar permisos mediante operaciones bit a bit.

Sin embargo, no siempre es necesario usar enumerados. En muchos casos, especialmente en librerías como Redux en React, donde se necesitan identificadores únicos para acciones, puede ser tentador usar enumerados, pero no siempre es la mejor solución. Los enumerados son útiles en situaciones concretas, pero no debemos abusar de ellos ni complicar demasiado nuestro código cuando existen alternativas más sencillas.

Por eso, es importante tener en cuenta cuándo realmente necesitamos enumerados y cuándo podemos optar por soluciones más simples. Así, mantenemos nuestro código claro y eficiente, usando enumerados con valores computados solo cuando aportan un beneficio real en la gestión de permisos o en otros casos similares.

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