Enums in TypeScript

Our enum type ServerState has an underlying numeric type. The possible values for ServerState are defined as constants.

enum ServerState {
    Idle,
    Connected,
    Error,
    Retrying
}

By implementing a toString method, values of ServerState can be printed out or converted to strings.

This can get cumbersome if there are many possible values. In such cases, automation tools can be used to generate these methods.

const stateName: Record<ServerState, string> = {
    [ServerState.Idle]: 'idle',
    [ServerState.Connected]: 'connected',
    [ServerState.Error]: 'error',
    [ServerState.Retrying]: 'retrying'
};

ServerState.toString = function (state: ServerState): string {
    return stateName[state];
};

If we have a value of a basic numeric type, TypeScript’s type system will ensure we can’t mistakenly treat it as a ServerState.

function main() {
    const ns = transition(ServerState.Idle);
    console.log(ServerState.toString(ns));
    
    const ns2 = transition(ns);
    console.log(ServerState.toString(ns2));
}

The transition function emulates a state transition for a server; it takes the existing state and returns a new state.

function transition(s: ServerState): ServerState {
    switch (s) {
        case ServerState.Idle:
            return ServerState.Connected;
        case ServerState.Connected:
        case ServerState.Retrying:
            return ServerState.Idle;
        case ServerState.Error:
            return ServerState.Error;
        default:
            throw new Error(`unknown state: ${s}`);
    }
}

main();

To run the program, use a TypeScript compiler:

$ tsc enums.ts
$ node enums.js
connected
idle

By implementing such patterns, we ensure a degree of type safety and clarity in how different states of our application can transition.