DEV Community

John Au-Yeung
John Au-Yeung

Posted on

All We Need to Know About TypeScript Enums

Subscribe to my email list now at http://jauyeung.net/subscribe/

Follow me on Twitter at https://twitter.com/AuMayeung

If we want to define constants in JavaScript, we can use the const keyword. With TypeScript, we have another way to define a set of constants call the enums. Enums let us define a list of named constants. It’s handy for defining an entity that can take on a few possible values. TypeScript provides both numeric and string-based enums.

Numeric Enums

TypeScript has an enum type that’s not available in JavaScript. An enum type is a data type that has a set named values called elements, members, enumeral or enumerator of the type. They’re identifiers that act like constants in the language. In TypeScript, a numeric enum has a corresponding index associated with it. The members start with the index 0 by default, but it can be changed to start at any index we like and the subsequent members will have indexes that increment from that starting number instead. For example, we can write the following code to define a simple enum in TypeScript:

enum Fruit { Orange, Apple, Grape };

We can use enums by accessing the members like any other property. For example, in the Fruit enum, we can accept the members like in the following code:

console.log(Fruit.Orange);  
console.log(Fruit.Apple);  
console.log(Fruit.Grape);

Then console.log from the code above should get us 0 since we didn’t specify a starting index for the enum. We can specify the starting index of an enum with something like in the following code:

enum Fruit { Orange = 1, Apple, Grape };  
console.log(Fruit.Orange);  
console.log(Fruit.Apple);  
console.log(Fruit.Grape);

Then we get the following logged from each console.log statement in order:

1  
2  
3

We can specify the same index for each member, but it wouldn’t be very useful:

enum Fruit { Orange = 1, Apple = 1, Grape };  
console.log(Fruit.Orange);  
console.log(Fruit.Apple);  
console.log(Fruit.Grape);

Then we get:

1  
1  
2

from the console.log. As we can see, we specify the index pretty much however we want to change it. We can even have negative indexes:

enum Fruit { Orange = -1, Apple, Grape };  
console.log(Fruit.Orange);  
console.log(Fruit.Apple);  
console.log(Fruit.Grape);

Then we get:

-1  
0  
1

from the console.log. To get an enum member by its index, we can just use the bracket notation like we access array entries by its index. For example, we can write the following code:

enum Fruit { Orange, Apple, Grape };  
console.log(Fruit[0]);  
console.log(Fruit[1]);  
console.log(Fruit[2]);

Then we get:

Orange  
Apple  
Grape

Numeric enums can have computed values assigned to their members. For example, we can write a function to get a value for each enum member like in the following code:

const getValue = () => 2;
enum Fruit {  
  Orange = getValue(),  
  Apple = getValue(),  
  Grape = getValue()  
};

Note that we assigned a return value for each member. If we don’t do that for all of them like in the following code:

const getValue = () => 2;
enum Fruit {  
  Orange = getValue(),  
  Apple = getValue(),  
  Grape  
};

Then the TypeScript compiler won’t compile the code and will give an error “Enum member must have initializer.(1061)“. We can mix both constant and computed values in one enum, so we can write something like:

const getValue = () => 2;
enum Fruit {  
  Orange = getValue(),  
  Apple = 3,  
  Grape = getValue()  
};

String Enums

TypeScript enum members can also have string values. We can set the values of each member to a string by assigning strings to them like in the following code:

enum Fruit {  
  Orange = 'Orange',  
  Apple = 'Apple',  
  Grape = 'Grape'  
};

However, unlike numeric enums, we can’t assign computed values to them. For example, if we have the following:

const getValue = () => 'Orange';
enum Fruit {  
  Orange = getValue(),  
  Apple = 'Apple',  
  Grape = 'Grape'  
};

Then we would get the TypeScript compiler error message “Computed values are not permitted in an enum with string-valued members. (2553)” since computed values aren’t allowed for string-valued enums. String enums don’t have auto-incrementing behavior like numeric enums since they don’t have numerical values, but the values of the enum members are much clearer since each value is a meaningful value that’s clear to any human reading it.

In a single enum, we can have some members having numeric values and others having string values like in the following code:

enum Fruit {  
  Orange = 2,  
  Apple = 'Apple',  
  Grape = 'Grape'  
};

However, this is more confusing than having a single type of value for all enum members, so it’s not recommended to have mixed value types for different members for an enum.

Computed and Constant Members

Each enum member has a value associated with it which can either be constant or computed. An enum member is constant if the first member in the enum has no value explicitly assigned to it, which means that it’s assigned the value 0 by default. It can also be considered constant if it doesn’t have an explicit value assigned to it and the preceding enum member was a numeric constant, which means that it’ll have the value of the preceding member plus one. For example, if we have:

enum Fruit { Orange = 1, Apple, Grape };

Then Apple and Grape are both constant members since it’ll be automatically assigned the values 2 and 3 respectively. They’re also considered constant if each member has string values assigned to them. Also, if an enum references a previously defined enum member which can be from the same or a different enum. The return value of any operation assigned to constant enums like surrounding an enum expression with parentheses, doing unary arithmetic or bitwise operations to an enum expression like +, -, ~, or doing binary arithmetic or bitwise operations like, -, *, /, %, <<, >>, >>>, &, |, ^ with enum expressions as operands are all considered constant enum expressions.

For example, the following enum is an enum with constant enum expressions:

enum Fruit {  
  Orange = 1 + 2,  
  Apple =  1 + 3,  
  Grape = 1 + 4  
};

The expressions are constant since they’re computed from any variable or return values of functions. Each member has values that's computed from number values, rather than numbers assigned to variables or returned from functions.

The following is also an example of an enum with constant members:

enum Fruit {  
  Orange = 1 + 2,  
  Apple =  1 + 3,  
  Grape = Orange + Apple  
};

All the members including the last one are constant since the value of Grape is computed from Orange and Apple which are constant. Bitwise operations with both operands being constant values are also considered constants as we have in the following code:

enum Fruit {  
  Orange = 1 | 2,  
  Apple =  1 + 3,  
  Grape = 'abc'.length  
};

Anything else not described above is considered computed values. For example, if we have:

enum Fruit {  
  Orange = 1 + 2,  
  Apple =  1 + 3,  
  Grape = 'abc'.length  
};

Then Grape is a computed member since the expression we assigned to Grape is not computed from any constant member, and it involves getting a property from an object, which isn’t computed from a constant value.

If we want to define constants in JavaScript, we can use the const keyword. With TypeScript, we have another way to define a set of constants call the enums. Enums let us define a list of named constants. It’s handy for defining an entity that can take on a few possible values. TypeScript provides both numeric and string-based enums. TypeScript allows enum members to have numeric and string values. They can also be computed from values for other enum members or from any other expression we wish to assign. Constant enums are the ones that are computed from actual numerical values as operands or with actual values assigned to the member. All other values are computed member values.

Top comments (0)