[typescript] Enum & const

kelly woo
4 min readMar 21, 2021
Photo by pine watt on Unsplash

First time I used typescript, enum was great, but by some reasons I stopped using it in typescript. And this article is to demonstrate why I stopped using.

https://www.typescriptlang.org/docs/handbook/enums.html

| Enum into plain javascript

enum ActionType {
ADD = 'ADD',
SUB= 'SUB',
MULT= 'MULT',
DIV = 'DIV'
}

Typescript generates enum object in plain javascript like this shape.
with var keyword, it is translated into Immediately-Invoked Function Expression(IIFE).

var ActionType;
(function (ActionType) {
ActionType["ADD"] = "ADD";
ActionType["SUB"] = "SUB";
ActionType["MULT"] = "MULT";
ActionType["DIV"] = "DIV";
})(ActionType || (ActionType = {}));

This is not a big problem, but some might be bothered by this result, first it uses var keyword which does not go along with the concept of constant, and second, it harms tree-shaking by using IIFE, many bundlers like webpack or rollup consider this code is used with IIFE.
Also it is unnecessarily long code.

| Unexpected result

enum ActionType {
ADD,
SUB,
MULT,
DIV,
}

This is another way to declare enum, and when we declare this way, the result is as following.

ActionType.ADD === 0& ActionType[0] === 'ADD'

Because this enum generates key and value with index, js code is like the below.

var ActionType;
(function (ActionType) {
ActionType[ActionType["ADD"] = 0] = "ADD";
ActionType[ActionType["SUB"] = 1] = "SUB";
ActionType[ActionType["MULT"] = 2] = "MULT";
ActionType[ActionType["DIV"] = 3] = "DIV";
})(ActionType || (ActionType = {}));
// result into {
"0": "ADD",
"1": "SUB",
"2": "MULT",
"3": "DIV",
"ADD": 0,
"SUB": 1,
"MULT": 2,
"DIV": 3
}

Adding on, if there are 2 ActionTypes who have different keys

enum ActionType {
add = 'ADD',
sub = 'SUB',
mult = 'MULT',
div = 'DIV'
}
enum ActionType {
ADD,
SUB,
MULT,
DIV,
}

They do not give an error(unless the key is not duplicated), instead it combines the results.

var ActionType;
(function (ActionType) {
ActionType["add"] = "ADD";
ActionType["sub"] = "SUB";
ActionType["mult"] = "MULT";
ActionType["div"] = "DIV";
})(ActionType || (ActionType = {}));
(function (ActionType) {
ActionType[ActionType["ADD"] = 0] = "ADD";
ActionType[ActionType["SUB"] = 1] = "SUB";
ActionType[ActionType["MULT"] = 2] = "MULT";
ActionType[ActionType["DIV"] = 3] = "DIV";
})(ActionType || (ActionType = {}));
/** the result
{
"0": "ADD",
"1": "SUB",
"2": "MULT",
"3": "DIV",
"add": "ADD",
"sub": "SUB",
"mult": "MULT",
"div": "DIV",
"ADD": 0,
"SUB": 1,
"MULT": 2,
"DIV": 3
}
**/

| const enum

const enum is great at first glance by replacing, but not declaring in plain js. Declaration part is removed and only value is referred.

let value = 2; /* Name */

But if you are trying to export it, it won’t work (most articles say it won’t work if isolatedModules is true, but I couldn’t make it work either cases. — https://ncjamieson.com/dont-export-const-enums/)

Check Exampleconst enum ActionType {
add = 'ADD',
sub = 'SUB',
mult = 'MULT',
div = 'DIV'
}
const a = ActionType.add;// generated code is only the below..
// const a = "ADD" /* add */;

| Alternative

Then how we declare enum..ish variables?

Just use plain const object and add some hint code.

Check hereconst ActionType = {
ADD: 'ADD',
SUB: 'SUB',
MULT: 'MULT',
DIV: 'DIV'
} as const
type ActionType = typeof ActionType[keyof typeof ActionType];
const a:ActionType = 'ADD'; //(OK!!!!)

This is to get the value of ActionType and make them a type.
You might wonder about as const

as constis to prevent mutation of the type.

Without as const this code goes silent, and we do not want this.

Check here.const ActionType = {
ADD: 'ADD',
SUB: 'SUB',
MULT: 'MULT',
DIV: 'DIV'
}
type ActionType = typeof ActionType[keyof typeof ActionType];
ActionType.ADD = 'ADD2' // hey!!! I changed the value..
const a:ActionType = 'ADD'; // but no error without as const

Since const does not prevent mutation of its property, it is still mutable and typescript lost track of the type. So we put as const to make sure no further mutation.

But what if it is important data?

| Object.freeze

Enum and as const are only tool for typescript, it is not directly in charge of preventing mutation of real plain javascript.
Most time the data are not important, so won’t be a problem by using readonly or enum or const, but if it is important, I think you know what you should do. freeze it. :)

Check exampleconst ActionType = Object.freeze({
ADD: 'ADD',
SUB: 'SUB',
MULT: 'MULT',
DIV: 'DIV'
})
type ActionType = typeof ActionType[keyof typeof ActionType];ActionType.ADD = 'ADD2' // error

--

--