TypeScript Enums

Enums, short for Enumerations, represent a new data type available in TypeScript. They serve to establish a collection of named constants, which are essentially a group of associated values. TypeScript accommodates both numeric and string-based enums. Enums can be defined utilizing the keyword enum.

Enums enhance code readability and maintainability by enabling the use of descriptive names for collections of values. They are especially beneficial when handling values that are logically associated, such as days of the week, cardinal directions, or user roles.

Why Enums?

Enums are useful in TypeScript because of the following:

  • It makes it easy to change values in the future.
  • It reduces errors which are caused by transporting or mistyping a number.
  • It exists only during compilation time, so it does not allocate memory.
  • It saves runtime and compile-time with inline code in JavaScript.
  • It allows us to create constants that we can easily relate to the program.
  • It will enable developers to develop memory-efficient custom constants in JavaScript, which does not support enums, but TypeScript helps us to access them.

TypeScript features three distinct varieties of Enums, which are as follows:

  • Numeric Enums
  • String Enums
  • Heterogeneous Enums
  • Numeric Enums

Numeric enums are enumerations that utilize numbers to represent their values. This allows for the assignment of numerical values to instances of the enum.

Example

Example

enum Direction {

    Up = 1,

    Down,

    Left,

    Right,

}

console.log(Direction);

Explanation:

In the example provided, there exists a numeric enumeration called Direction. In this case, Up is assigned the value of 1, with each subsequent member automatically incremented from that point. Thus, Direction.Up equates to 1, Direction.Down corresponds to 2, Direction.Left represents 3, and Direction.Right is valued at 4.

Output:

Output

{

  '1': 'Up',

  '2': 'Down',

  '3': 'Left',

  '4': 'Right',

  Up: 1,

  Down: 2,

  Left: 3,

  Right: 4

}

In accordance with our requirements, it also permits us to omit the enumeration initialization. We can define the enum without any initialization, as illustrated in the example below.

Example

Example

enum Direction {

    Up,

    Down,

    Left,

    Right,

}

console.log(Direction);

Explanation:

In this instance, Up is not given a specific value, prompting TypeScript to automatically assign it a numeric value beginning at 0, with each subsequent member increasing by 1. Consequently, Direction.Up is assigned the value 0, Direction.Down is 1, Direction.Left is 2, and Direction.Right is 3. This automatic incrementing feature is advantageous when the actual values of the members are not a concern. However, it is essential that each value remains unique within the same enum.

Output:

Output

{

  '0': 'Up',

  '1': 'Down',

  '2': 'Left',

  '3': 'Right',

  Up: 0,

  Down: 1,

  Left: 2,

  Right: 3

}

Explanation:

In TypeScript enums, it is not mandatory to allocate sequential values to the members of the enum. We can assign any values to the enum members, as demonstrated in the following example.

Example

Example

enum Direction {

    Up=1,

    Down=3,

    Left=6,

    Right=10,

}

console.log(Direction);

Output:

Output

{

  '1': 'Up',

  '3': 'Down',

  '6': 'Left',

  '10': 'Right',

  Up: 1,

  Down: 3,

  Left: 6,

  Right: 10

}

Enum as a function argument

An enum can also serve as a type for functions or as a return type, as illustrated in the example below.

Example

Example

enum AppStatus {

    ACTIVE,

    INACTIVE,

    ONHOLD

} 

function checkStatus(status: AppStatus): void {

    console.log(status);

}

checkStatus(AppStatus.ONHOLD);

Explanation:

In the previous illustration, an enum named AppStatus has been defined. Following this, we implement a function called checkStatus that accepts a parameter named status and returns an enum AppStatus. Within this function, we evaluate the type of status. If the name of status corresponds, we retrieve the corresponding enum member.

Output:

Explanation:

In this example, the output '2' from the final statement is often not very helpful in various situations. Therefore, it is advisable and recommended to utilize string-based enums.

String Enums

String enums share a comparable idea with numeric enums, but they exhibit some nuanced distinctions during runtime. In a string enum, each value is initialized as a constant using a string literal or by referencing another member of the string enum, as opposed to using numeric values.

String enums lack the functionality of auto-incrementing. The advantage of utilizing this type of enum is that string enums enhance clarity. During program debugging, string enums enable us to present a significant and understandable value during execution, regardless of the enum member's name.

Examine the subsequent instance of a numeric enumeration, although it is depicted as a string enumeration:

Example

Example

enum AppStatus {

    ACTIVE = 'ACT',

    INACTIVE = 'INACT',

    ONHOLD = 'HLD',

    ONSTOP = 'STOP'

}

function checkStatus(status: AppStatus): void {

 

    console.log(status);

}

checkStatus(AppStatus.ONSTOP);

Output:

Explanation:

In the previous example, a string enum named AppStatus has been defined with identical values to the numeric enum mentioned earlier. However, string enums differ from numeric enums in that their values are set using string literals. The key distinction between these two types of enums lies in the fact that numeric enum values are automatically incremented, whereas string enum values must be assigned explicitly.

Heterogeneous Enums

Heterogeneous enums comprise both string and numeric values. However, it is recommended to avoid this practice unless it is necessary to leverage the behavior of the JavaScript runtime.

Example

Example

enum AppStatus {

    ACTIVE = 'Yes',

    INACTIVE = 1,

    ONHOLD = 2,

    ONSTOP = 'STOP'

}

console.log(AppStatus.ACTIVE);

console.log(AppStatus.ONHOLD);

Output:

Output

Yes

2

Explanation:

The AppStatus enumeration is categorized as a heterogeneous enum due to its combination of string and numeric values. However, reverse mapping is exclusively functional with numeric types and does not apply to standard string enumerations.

In the code, ACTIVE is defined as 'Yes' (a string), INACTIVE is set to 1 (a numeric), ONHOLD is assigned the value 2 (a numeric), and ONSTOP is represented as 'STOP' (a string). When you log AppStatus.ACTIVE, it outputs 'Yes', while logging AppStatus.ONHOLD produces the value 2.

Computed and constant members

It is understood that every enum member is linked to a value. These values may be either fixed or derived. An enum member can be regarded as constant if:

  1. It is the initial member of the enum and lacks an initializer value. In this scenario, it is allocated the value 0.
  2. Example

    Example
    
    // Name.Abhishek is constant:
    
    enum Name { 
    
       Abhishek 
    
    }
    
    console.log(Name);
    

Output:

Output

{ '0': 'Abhishek', Abhishek: 0 }
  1. It lacks an initializer value, and the prior enum member is a numeric constant. Consequently, the value of the current enum member will equal the value of the preceding enum member incremented by one.
  2. Example

    Example
    
    // All enum members in 'Name' and 'Profile' are constant.
    
    enum Name { 
    
       Abhishek,
    
       Ravi,
    
       Ajay
    
    }
    
    enum Profile { 
    
       Engineer=1,
    
       Leader,
    
       Businessman
    
    }
    

Output:

Output

{

  '0': 'Abhishek',

  '1': 'Ravi',

  '2': 'Ajay',

  Abhishek: 0,

  Ravi: 1,

  Ajay: 2

}

{

  '1': 'Engineer',

  '2': 'Leader',

  '3': 'Businessman',

  Engineer: 1,

  Leader: 2,

  Businessman: 3

}

In TypeScript, we can say that an expression is a constant enum expression if it is:

  • A literal enum expression.
  • A reference to the previously defined constant enum member.
  • A parenthesized constant enum expression.
  • It is one of the +, -, ~ unary operators which is applied to constant enum expression.
  • +, -, *, /, %, <<, >>, >>>, &, |, ^ binary operators with constant enum expressions as operands.

In all other instances, the enum member is regarded as computed. The subsequent enum illustration features enum members that possess computed values.

Example

Example

enum Weekend {

  Friday = 1,

  Saturday = getDate('Dominoz'),

  Sunday = Saturday * 40

}

function getDate(day : string): number {

    if (day === 'Dominoz') {

        return 3;

    }

}

console.log(Weekend.Saturday); 

console.log(Weekend.Sunday);

Output:

Output

3

120

Explanation:

In the preceding example of the Weekend enum, the value for Saturday is determined through the getDate function. The following function verifies whether the provided string is "Dominoz" and, if so, returns 3. Consequently, Saturday is assigned a value of 3, while Sunday is calculated as Saturday multiplied by 40, resulting in 120. This illustrates the potential usage of enums.

Reverse mapping

TypeScript enums allow for reverse mapping as well. This functionality enables users to retrieve both the value associated with an enum member and the name of a member using its value. The concept of reverse mapping can be illustrated with the example below.

Note: The string enum does not support reverse mapping.

Example

Example

enum Weekend {

  Friday = 1,

  Saturday,

  Sunday

}

console.log(Weekend.Saturday);   

console.log(Weekend["Saturday"]);  

console.log(Weekend[3]);

Output:

Output

2

2

Sunday

Explanation:

In this example, the Weekend enum begins with Friday assigned the value of 1, leading to Saturday being automatically assigned 2, and Sunday taking the value of 3. The value of 2 can be retrieved using both Saturday and Weekend["Saturday"]. If we examine Weekend[3], it executes a reverse lookup and yields the string "Sunday". This illustrates the dual mapping capability that enums provide in TypeScript.

Enums at runtime

Enums are actual entities that are present during runtime. This can be illustrated through the following example.

Example

enum E {

    A, B, C

}

It can indeed be transmitted to functions, as demonstrated in the example below.

Example

function f(obj: { A: number }) {

    return obj.A;

}

// Works, since 'E' has a property named 'A' which is a number.

f(E);

Ambient enums

Ambient enums can be utilized to characterize the structure of pre-existing enum types.

Example

Declare enum Enum{

    X=1,

    Y,

    Z=2

}

The primary distinction between ambient and non-ambient enums lies in their treatment of members without initializers. In standard enums, if a preceding enum member is deemed constant, any subsequent member lacking an initializer is also regarded as constant. Conversely, an ambient (and non-const) enum member without an initializer is consistently classified as a computed enum.

Use Cases

  1. Managing Application States

Enums are most effective when all potential states that need to be represented in an application are known, such as in user authentication (LOGGEDIN, LOGGEDOUT, PENDING) or in order processing (PLACED, SHIPPED, DELIVERED, CANCELLED).

  1. Defining Roles and Permissions

It is additionally utilized to identify user roles such as ADMIN, MODERATOR, and USER, along with access restrictions to certain sections of the system.

  1. Working with HTTP Status Codes

Extensive frameworks like Spring MVC offer enumerations for frequently used HTTP response statuses (e.g., OK = 200, NOTFOUND = 404, INTERNALSERVER_ERROR = 500), resulting in more organized and expressive API management code.

  1. UI Control and Visibility States

An Enum can verify user interface statuses such as VISIBLE, HIDDEN, DISABLED, and LOADING, facilitating a more organized approach to managing component behavior.

Frequently Asked Questions (FAQs)

Q1: What is an enum in TypeScript?

An enum, which stands for enumeration, is a distinct data type that allows the definition of a collection of named numeric constants in Python. Enums facilitate the creation of more understandable code and enable the logical association of certain values under a shared identifier.

Q2: What are the types of enums in TypeScript?

TypeScript supports three types of enums:

  • Numeric Enums (default)
  • String Enums
  • Heterogeneous Enums (a mix of string and numeric values)

Q3: Can enums have computed values?

Indeed, it is possible to retain values yielded by functions or expressions calculated for enum members. Nevertheless, computed members are required to undergo manual initialization.

Q4: Is reverse mapping possible with enums?

Indeed, reverse mapping is feasible exclusively with numeric enums. TypeScript establishes a mapping from names to values as well as from values to names. Conversely, string enums do not function in the same manner.

Q5: Can you explain what a const enum is and in what scenarios it is advisable to utilize it?

A const enum represents an enum optimized by the compiler that results in no code being produced in the final output. During the compilation process, it is fully eliminated, and its references are substituted with literal values. Utilize it when reverse mapping is unnecessary.

Q6: Is it possible to utilize enums in conditional statements or switch-case constructs?

Certainly. Although Enums are beneficial for conditional logic such as if statements or switch cases, their true strength lies in scenarios where the contents are regulated and the values are part of a defined collection of related items.

Q7: Are enums specific to TypeScript?

Enums are frequently utilized to establish user roles such as ADMIN, MODERATOR, and USER, and to manage access to particular sections of the system according to these roles.

Input Required

This code uses input(). Please provide values below: