As an Angular coach, I review a lot of Angular applications. One thing that I see in a lot of code bases is the use of Typescript enums to store a bunch of constants:
The above code creates a new type CompassDirection
with four possible values: CompassDirection.North
, CompassDirection.East
, etc.
Each constant gets assigned a numerical value starting at 0, so in that example, CompassDirection.North is equal to 0, and CompassDirection.North
is equal to 3.
These values can be customized, and we can use strings, objects, or anything we want instead of numbers:
And that’s about all you can do with enums in Typescript.
Why I avoid enums
I avoid enums because they’re neither convenient nor performant. For instance, this is what the last example gets compiled into by the Typescript compiler:
That’s not pretty, and it comes at the extra cost of all that code being downloaded in the browser and then interpreted, which impacts performance.
Also, enums aren’t very convenient to be used in component templates. If I want to use an enum in a component template, I need this additional code to make that type accessible on the component instance (the this
reference):
Instead, we could use a union type:
We still get a type associated with specific values, but now this gets compiled into the following:
No, I didn’t forget anything in that black rectangle: Union types are like interfaces and don’t get compiled into anything, meaning they do not increase the size of your code base or impact performance. Also, since those types are just the union of other types (such as strings or numbers), these constants can be used as-is in a component template without needing to tweak our component class.
In other words, union types preserve type safety without degrading our app’s performance, which is a win-win.