Enum implementation

When TypeScript generates the JavaScript for enums, it uses the closure and Immediately Invoked Function (IIF) patterns to define a JavaScript object with the correct properties that can be used as an enum. Let's take a look at this implementation. Given our DoorState enum, which is defined as follows:

enum DoorState { 
    Open, 
    Closed, 
    Ajar 
} 

We know that we can reference the DoorState.Open value, which will be represented as a numeric value of 0, Closed as 1, and Ajar as 2. But what happens if we reference an enum using an array-type syntax, as follows:

var ajarDoor = DoorState[2]; 
console.log(`ajarDoor is : ${ajarDoor}`); 

Here, we assign the variable ajarDoor to an enum value based on the second index value of the DoorState  enum. The output of this code, though, is surprising:

ajarDoor is : Ajar

You may have been expecting the output to simply be 2, but here we are getting the Ajar string, which is a string representation of our original enum value. This is actually a neat little trick allowing us to access a string representation instead of a simple number. The reason that this is possible is down to the JavaScript that has been generated by the TypeScript compiler. Let's take a look, then, at the closure that the TypeScript compiler has generated:

var DoorState; 
(function (DoorState) { 
    DoorState[DoorState["Open"] = 0] = "Open"; 
    DoorState[DoorState["Closed"] = 1] = "Closed"; 
    DoorState[DoorState["Ajar"] = 2] = "Ajar"; 
})(DoorState || (DoorState = {})); 

This strange looking syntax is building an object that has a specific internal structure. It is this internal structure that allows us to use this enum in the various ways that we have seen. If we interrogate this structure while debugging our JavaScript, we will see that the internal structure of the DoorState object is as follows:

DoorState 
{...} 
    [prototype]: {...} 
    [0]: "Open" 
    [1]: "Closed" 
    [2]: "Ajar" 
    [prototype]: [] 
    Ajar: 2 
    Closed: 1 
    Open: 0 

The DoorState object has a property called "0", which has a string value of "Open". Unfortunately, in JavaScript, the number 0 is not a valid property name, so we cannot access this property by simply using DoorState.0. Instead, we must access this property using either DoorState[0] or DoorState["0"]. Accessing the value of this property will return the string value of "Open". Note that the DoorState object also has a property named Open, which is set to the numeric value 0. The word Open is a valid property name in JavaScript, so we can access this property using DoorState["Open"], or simply DoorState.Open, which equates to the same JavaScript property.

Note that the internal structure of string enums does not have number-based properties, so we cannot use the enum[propertyIndex] syntax when using string enums.