Page Content

Tutorials

How to Create Enums in TypeScript?

Enums in TypeScript

In TypeScript, enums (also known as enumerations) offer a way to arrange a group of similar items. JavaScript lacks an enum data type, but several conventional programming languages, including C, C#, and Java, include one. Enums are introduced by TypeScript mainly to provide an optional type system that allows programmers to specify named constants that improve the readability and maintainability of code. They limit the values that can be assigned by listing all of the potential values for a certain type.

Number-based Enums and Constraining Values

TypeScript enums, often known as Number Enums, are by default number-based. The enum members are 0-based, and each new item automatically increases by one unless a value is specifically supplied.

Take, for example, the definition of a simple numeric enum:

enum Tristate {
    False,    // 0
    True,     // 1
    Unknown   // 2
}

Constraint and Type Safety: This construct limits the values that variables defined with the Tristate type can have. To ensure type safety, the compiler will raise an error if you try to assign a value that is incompatible with the numeric type that supports the enum (for example, a string).

// Example of type safety
enum CardSuit {
    Clubs,
    Diamonds,
    Hearts,
    Spades
}

var card = CardSuit.Clubs;
// card = "not a member of card suit"; // Error: string is not assignable to type `CardSuit` 

Flexibility with Numbers: An enum instance can be allocated actual numerical values because Number Enums are compatible with the primitive number type.

var col = Tristate.False;
col = 0; // OK: Effectively the same as Tristate.False

Changing Default Values: By explicitly allocating a number, you can modify the default numeric association for any enum member. From that assigned value, the incrementation process continues automatically.

enum Color {
    DarkRed = 3,       // 3
    DarkGreen,         // 4 (automatically increments from 3)
    DarkBlue           // 5
}

Runtime JavaScript Generation and Reverse Mapping: TypeScript creates JavaScript code that enables reverse lookups when it compiles a standard (non-const) Number Enum. This implies that you may get a member’s string name from its numeric value and vice versa.

Code Example: Number Enum and Generated Output

TypeScript CodeJavaScript Output (Excerpt)
typescript enum Status { Ready, Waiting }“`javascript var Status; (function (Status) { Status[Status[“Ready”] = 0] = “Ready”; Status[Status[“Waiting”] = 1] = “Waiting”; })(Status

Usage and Output: The generated JavaScript structure (e.g., Status[Status["Ready"] = 0] = "Ready") performs two assignments: one mapping the string key ("Ready") to the number value (0), and one performing the reverse mapping (number key 0 to string value "Ready").

enum Status { Ready, Waiting } 

console.log(Status);         
console.log(Status["Ready"]);   
console.log(Status[Status.Ready]);

Output:

"Ready"   // Reverse lookup: Status is "Ready" 
0         // Normal lookup: Status["Ready"] is 0 
"Ready"   // Status.Ready == 0, so Status is "Ready"

String-based Enums

Before TypeScript version 2.4, a common workaround for mocking string-based enums was to utilise union types in conjunction with string literal types. Nevertheless, string enums are natively supported since TypeScript 2.4, enabling string values for enum members.

String enums have the advantage of providing debuggerable and meaningful string values. String enums generally prohibit accidental assignment of incompatible primitive types, in contrast to Number Enums, where numeric compatibility permits assignment of any number (which might present safety issues, particularly if a zero or one is set when an unexpected value might violate logic). Simple string comparisons are supported using string enums.

Code Example: String Enum Definition and Usage

export enum EvidenceTypeEnum {
    UNKNOWN = '',
    PASSPORT_VISA = 'passport_visa',
    PASSPORT = 'passport',
    SIGHTED_STUDENT_CARD = 'sighted_tertiary_edu_id',
}

// Sample usage in TypeScript
const someStringFromBackend = 'passport'; 
const value = someStringFromBackend as EvidenceTypeEnum; 

if (value === EvidenceTypeEnum.PASSPORT) {
    console.log('You provided a passport');
    console.log(value);
}

Output:

You provided a passport 
passport

Using const Enums

When accessing a member, the normal enum procedure necessitates a runtime search of the variable (Tristate) and its property (Tristate.False), notwithstanding its usefulness. TypeScript permits an enum to be marked as a const enum in order to improve performance.

The compiler is instructed to do two things by the const modifier:

  1. Inlining: The compiler immediately substitutes the literal value (such as 0) for any instances of the enum member name (such as Tristate.False).
  2. No Runtime Generation: Since the enum definition’s usages are entirely inlined, the compiler does not produce any related JavaScript code for it.

Code Example: const Enum and Compiled Output

TypeScript CodeJavaScript Output (Illustration of Inlining)
typescript const enum Tristate { False, True, Unknown } var lie = Tristate.False;javascript var lie = 0;

Consequences of const: Some runtime capabilities, such reverse lookups (number-to-string conversion), are not feasible since a const enum does not generate a JavaScript object at runtime. A compiler error occurs when you try to access a member using a non-string literal variable or do a reverse lookup.

Using the NinjaActivity const enum, for instance:

const enum NinjaActivity { Espionage, Sabotage, Assassination }

// TypeScript attempts to access enum dynamically:
// console.log(NinjaActivity[myFavoriteNinjaActivity]); 
// Error: A const enum member can only be accessed using a string literal. 

Preserving the Enum Definition: The compiler flag --preserveConstEnums can be used if you need the runtime definition of the enum but still want the speed advantage of inlining (for example, in manual number-to-string lookups). Despite usages remaining inline, this flag guarantees that the standard var EnumName definition is generated in the JavaScript output.

In Conclusion

Enums are a strong type feature in TypeScript that provide improved safety and debuggability through string-based declarations and flexibility through number-based defaults (TS 2.4+). By enabling compile-time inlining and removing needless runtime artefact production, the const keyword offers an optimisation method.

Index