leanmind logo leanmind text logo

Blog

Refactorización Avanzada

Dominar el refactoring productivo para maximizar el retorno de la inversión.

Enums en Typescript ¿Buenos o malos?

Por Adrián Ferrera González

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 de estar hablando acerca de FrontEnd, los tiempos de carga y la experiencia de usuario son un punto de gran peso.

En otros ámbitos como puede ser el BackEnd de una aplicación, este argumento deja de tener relevancia, puesto que los usuarios no se ven afectado por ello, y de forma general, el espacio en disco de un servidor no cobra especial relevancia en los sistemas actuales.

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

¿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 tales como: un conjunto de tipos, valores numéricos o estados del sistema; que pueden ser reutilizadas en cualquier parte del código.

Esto sirve especialmente para evitar errores de escritura, eliminar definición de valores por todo nuestro código y por consiguiente facilitar refactors, centralizando los mismos.

Este concepto no es nativo de JavaScript, sino que viene heredado de Java, por lo que cuando usemos este tipo de definiciones tendrán que ser transpilados a nativo de forma similar a como ocurre con las clases y los métodos privados en ES5.

Así pues la apariencia de un enum en Typescript es la siguiente:

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

Sin embargo al ser transpilado obtenemos el siguiente resultado:

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

¿Cómo mejorarlo?

Si bien no es que suponga un cambio radical en cuanto al código, si que podemos mejorar la performance usando un concepto más simple y cercano al cómo se haría esto en Javascript.

Para ello no haremos otra cosa que definir una constante, a la cual asignaremos un objeto con propiedades y forzaremos usando el as que dicha variable o propiedad no puede ser mutada:

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

// or better
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'
};
// or better
const Fruits2 = {
    orange: 'orange',
    apple: 'apple'
};

Como podemos observar, el resultado es el mismo.Recordemos que ciertas funcionalidades como los types y las interface solo existen en el ámbito de Typescript y no son transpiladas a Javascript.

Ahora bien, ¿qué diferencia existe entre la primera y la segunda definición de Fruits mostrada anteriormente? Simplemente el como Typescript interpreta dicha variable. Veamos el mensaje de error mostrado si intentamos mutar la constante:

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)

Siendo más correcta la segunda forma debido al error que muestra en caso que intentemos mutar el objeto.

Conclusión

Es cierto que Typescript es una herramienta muy potente para los desarrolladores y que, salvo contados casos, debemos primar la mantenibilidad frente al rendimiento, sin embargo, cuando tenemos que prestar especial atención al rendimiento, podemos desechar determinadas herramientas del Superset en pos de usarlo tal y como haríamos en Javascript, sin perder legibilidad puesto que son herramientas que ya son nativas en el sistema.

Ulises Santana

Después de leer el artículo me dió por juguetear en un playground con el ejemplo y me he dado cuenta de que la alternativa del enum no vale para todos los casos.

Concretamente en el caso en el que quieres usar ese enum como un tipo para asegurarte que cuando se lo pasas como parámetro a una función sean sólo los valores que esperas. En este caso el objeto plano de JavaScript ya que es un valor, no un tipo.

enum|642x499

En conclusión, la alternativa nos sirve a nivel de valor, pero no como tipo y valor que es lo que aporta el enum en TypeScript.

UPDATE: navegando por Stack Overflow he encontrado esta solución: si fuéramos a usar la opción del objeto en JavaScript, en vez de fruit: Fruits sería fruit: typeof Fruits2[keyof typeof Fruits2]. Es más verboso que el enum, pero igualmente válido.

Publicado el 11/04/2022 por
Adrián image

Adrián Ferrera González

https://adrianferrera.dev

¿Quieres más? te invitamos a suscribirte a nuestro boletín para avisarte cada vez que recopilemos contenido de calidad que compartir.

Si disfrutas leyendo nuestro blog, ¿imaginas lo divertido que sería trabajar con nosotros? ¿te gustaría?

Impulsamos el crecimiento profesional de tu equipo de developers