Cómo iterar un enum para botones de radio en TypeScript: tutorial

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Por qué enum y botones de radio son la pareja ideal?

\n

Imagina: estás escribiendo un formulario en TypeScript. Necesitas que el usuario elija una opción entre varias — por ejemplo, nivel de dificultad, estado del pedido o género. ¿Dónde almacenar estas opciones? Podrías hardcodear un array de strings, pero eso no lleva a ningún lado. Cuando haya muchas opciones, te confundirás, y si la lógica de negocio cambia, tendrás que modificar el código en diez lugares.

\n

Aquí entran en escena los enum (enumeraciones). Permiten definir un conjunto de constantes con nombre que son legibles para los humanos y comprensibles para la máquina. Y los botones de radio son el elemento UI clásico para seleccionar un único valor de una lista. Combinarlos significa obtener un código limpio y mantenible. Suena genial, pero hay un detalle: ¿cómo iterar exactamente un enum para mostrarlo en la plantilla? Esta es la pregunta que atormenta a miles de desarrolladores en Stack Overflow. Vamos a resolverlo de una vez por todas.

\n\n

El problema: un enum no es un array

\n

En TypeScript, un enum no es simplemente una lista de strings. Dependiendo de cómo lo declares (numérico o de strings), se comporta de manera diferente. Un enum numérico crea una relación inversa: clave -> valor y valor -> clave. Uno de strings, solo la directa. Por lo tanto, simplemente escribir for (let item in MyEnum) es una mala idea. Obtendrás no solo las claves deseadas, sino también mapeos inversos no deseados.

\n

Así es como se ve una trampa típica:

\n
enum Status {\n  Active = 1,\n  Inactive = 2,\n  Pending = 3\n}\n\n// NO hagas esto\nfor (let key in Status) {\n  console.log(key); // "1", "2", "3", "Active", "Inactive", "Pending"\n}\n
\n

¿Ves? En la consola aparecen tanto los nombres como los valores. Si intentas mostrar esto en botones de radio, el usuario verá números sin sentido. Eso no nos sirve.

\n\n

Solución n.º 1: Object.values() para enums de strings

\n

La forma más simple y confiable es usar Object.values(). Este método devuelve un array de los valores de las propiedades enumerables de un objeto. Para enums de strings funciona perfectamente, porque (casi siempre) no tienen mapeo inverso.

\n\n

Ejemplo: estado del pedido

\n
enum OrderStatus {\n  New = 'new',\n  Processing = 'processing',\n  Shipped = 'shipped',\n  Delivered = 'delivered',\n  Cancelled = 'cancelled'\n}\n\n// Obtenemos el array de valores\nconst statusValues = Object.values(OrderStatus);\n// ['new', 'processing', 'shipped', 'delivered', 'cancelled']\n\n// Ahora se puede mostrar fácilmente en la plantilla (React)\nfunction StatusSelector() {\n  return (\n    <div>\n      {statusValues.map((status) => (\n        <label key={status}>\n          <input type="radio" name="status" value={status} />\n          {status}\n        </label>\n      ))}\n    </div>\n  );\n}\n
\n

Todo es brillantemente simple. Obtuvimos un array de strings y simplemente lo iteramos. Funciona para React, Angular, Vue — cualquier framework.

\n\n

Solución n.º 2: Object.keys() + filtrado para enums numéricos

\n

Con los enums numéricos la situación es más complicada. Object.values() devolverá no solo las claves de tipo string, sino también los valores numéricos, porque JavaScript los considera "propiedades" del objeto. Necesitamos filtrar solo los strings (claves).

\n\n

Ejemplo: nivel de acceso

\n
enum AccessLevel {\n  Guest = 0,\n  User = 1,\n  Moderator = 2,\n  Admin = 3\n}\n\n// Filtramos: dejamos solo los strings (claves)\nconst levelKeys = Object.keys(AccessLevel).filter(key => isNaN(Number(key)));\n// ['Guest', 'User', 'Moderator', 'Admin']\n\n// Si necesitas un array de objetos para una visualización más cómoda\nconst levelOptions = levelKeys.map(key => ({\n  label: key,\n  value: AccessLevel[key as keyof typeof AccessLevel]\n}));\n// [\n//   { label: 'Guest', value: 0 },\n//   { label: 'User', value: 1 },\n//   ...\n// ]\n
\n

Ahora tienes un array de opciones, donde label es un nombre legible para humanos y value es un código numérico que es conveniente

Blogs

Book Recommendations