Alternatives to TypeScript enum

enum Shape { Line = 0 }; enum Shape { Dot = 0 }; const x: Shape.Dot = Shape.Line;

TypeScript, like many programming languages provides enums, which enable you to enumerate the values a type may have.

TS enums look like this:

I’ll go into:

  • Alternatives to enums: string unions and object literals
  • How enum is terrible

Note: TS is a fantastic programming language, and enum may have been a good choice back in 2011 when good alternatives did not exist.

Alternative 1: String Unions

This solution uses a union of string literal types.

TS gives great autocompletes for these, and gives helpful error messages if you make type errors.

Pros of the approach:

  • Both the definition and use sites are readable and no-boilerplate

Cons:

  • The JS output looks the same as the TS, except without the type declaration and : Directionannotation. Which is great! But it's not the kind of JS a normal JS dev would write. The next solution is classic JS style, but is a bit clunky in TS.

Note: number literal types provide an alternative to numeric enums: type ENV_ID = 1

Alternative 2: Object Literals

This solution is just standard JS pseudo-enums with some quirky annotations:

It works!:

The solution relies on the following advanced TS features:

  • const assertions to not lose the information about the specific strings in the object.
  • typeof to get the type of a variable
  • keyof to get a union type for the keys of the object.
  • union types
  • lookup types to index into an object type
  • The distributivity of union types: ObjType["A" | "B"] is the same as ObjType["A"] | ObjType["B"]
  • the trick that a type aliases and constants live in separate worlds, so can have the same spelling.

Pros of the plain objects approach:

  • This solution is the most straightforward I have seen for cases for converting existing JS files to TS.
  • Compiles to really normal JS

Cons:

  • The reason JS devs write things like DIRECTIONS.UP instead of just "UP" is so they don't end up with semi-hardcoded strings everywhere. But TS's autocomplete will actually fight to mitigate this advantage. Note the autocomplete in the example above is not DIRECTIONS.UP but the plain string "UP".
  • The solution might induce cargo-culting or scare people away from TypeScript.

How enum is terrible (now that there are better alternatives)

Issue 1: The transpile output of enum is super weird, which builds lock-in to TS and impairs debuggability:

outputs:

Issue 2: enum values default to numbers (not strings), which is also bad for debuggability:

Issue 3: Using TS runtime features means you may have to deal with breaking changes if JS evolves a similar feature with different semantics. There is already a conflicting proposal for enum in JS. This sort of thing has happened before:

Issue 4: The assignability rules don’t make sense:

Issue 5: Declaration merging is pretty scary:

TypeScript, the Line is a Dot to you!

Noting again: TS is a fantastic programming language, and enum may have been a good choice back in 2011 when better alternatives did not exist.

Related Reading

These pro-enum posts to provide an alternative perspective:

--

--

Views are my own

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store