← Volver al blog Post

Enums en TypeScript ¿Buenos o malos?

Publicado originalmente en Lean Mind.

Introducción

Uno de los grandes motivos para argumentar el no usar TypeScript suele ser que el tamaño del bundle generado es mayor que si el código se escribiese de forma nativa en JavaScript. Y no le falta peso a este argumento, puesto que si estamos hablando de frontend, los tiempos de carga y la experiencia de usuario tienen un peso importante.

En otros ámbitos, como puede ser el backend de una aplicación, este argumento pierde relevancia, puesto que las personas usuarias no se ven afectadas directamente y, de forma general, el espacio en disco de un servidor no suele ser un problema significativo en los sistemas actuales.

Sin embargo, volviendo al primer caso, hay ciertas decisiones que podemos tomar a la hora de escribir código para mejorar el tamaño de nuestros bundles. Una de ellas es tener en cuenta a qué se transpila cada elemento que definimos y buscar alternativas.

¿Qué es un enum en TypeScript?

Un enum no es más que envolver en un objeto determinadas propiedades como constantes estáticas con valores específicos del negocio, como un conjunto de tipos, valores numéricos o estados del sistema, que pueden reutilizarse en cualquier parte del código.

Esto sirve especialmente para evitar errores de escritura, eliminar la repetición de valores por todo el código y facilitar futuros refactors al centralizar esos valores.

Este concepto no es nativo de JavaScript, sino heredado de Java, por lo que cuando usamos este tipo de definiciones tienen que transpilarse a JavaScript, de forma parecida a lo que ocurre con las clases o los métodos privados en ES5.

Así pues, la apariencia de un enum en TypeScript sería esta:

export enum Fruits {
  apple = 'apple',
  orange = 'orange',
}

Sin embargo, al transpilarlo obtenemos algo parecido a esto:

"use strict";
var Fruits;
(function (Fruits) {
  Fruits["orange"] = "orange";
  Fruits["apple"] = "apple";
})(Fruits || (Fruits = {}));

¿Cómo mejorarlo?

Aunque no suponga un cambio radical en el código, sí podemos mejorar la performance usando un concepto más simple y más cercano a cómo lo haríamos en JavaScript.

Para ello no haremos otra cosa que definir una constante, asignándole un objeto con propiedades y forzando con as const que dicha variable o propiedad no pueda mutarse.

const Fruits = {
  orange: 'orange' as const,
  apple: 'apple' as const,
}

// o mejor
const Fruits2 = {
  orange: 'orange',
  apple: 'apple',
} as const

En JavaScript esto se traduciría de la siguiente forma:

"use strict";
const Fruits = {
  orange: 'orange',
  apple: 'apple',
};

const Fruits2 = {
  orange: 'orange',
  apple: 'apple',
};

Como podemos observar, el resultado es mucho más directo. Recordemos además que ciertas funcionalidades, como los types y las interface, solo existen en el ámbito de TypeScript y no son transpilaradas a JavaScript.

Ahora bien, ¿qué diferencia existe entre la primera y la segunda definición de Fruits? Simplemente cómo TypeScript interpreta la variable. Veamos el mensaje de error mostrado si intentamos mutarla:

Fruits.apple = 'apple2'
// Type '"apple2"' is not assignable to type '"apple"'.(2322)

Fruits2.apple = 'apple2'
// Cannot assign to 'apple' because it is a read-only property.(2540)

La segunda forma es más correcta por el tipo de error que genera al intentar mutar el objeto.

Conclusión

Es cierto que TypeScript es una herramienta muy potente y que, salvo casos concretos, debemos priorizar la mantenibilidad frente al rendimiento. Sin embargo, cuando necesitamos prestar una atención especial al rendimiento, podemos desechar determinadas herramientas del superset y optar por soluciones más cercanas a JavaScript sin perder legibilidad.

Después de leer el artículo, Ulises Santana compartió una observación interesante: la alternativa basada en objetos no sirve para todos los casos si necesitamos usar ese valor también como tipo. En ese escenario, el enum sigue aportando valor porque combina tipo y valor. Como alternativa, se puede usar typeof Fruits2[keyof typeof Fruits2], aunque resulte más verboso.

enum-feedback

  • typescript
  • javascript
  • performance