TypeScript is well-loved by the developer neighborhood for a lot of causes, certainly one of which is due to the static checks it offers to the code written in it.
Recognizing issues early in your improvement lifecycle can save days of debugging random, imprecise errors that may typically pop up when utilizing dynamic languages like JavaScript.
TypeScript may help make your code extra predictable and higher documented, make refactoring simpler, and assist cut back potential errors you would possibly face at runtime in your manufacturing app. Its recognition and energy are demonstrated by its 93% developer satisfaction fee and its skyrocketing utilization over the previous 5 years.
One language mechanism that’s pivotal to TypeScript is enums. On this article, we’ll focus on:
What are enums in TypeScript?
Enums aren’t a function of typing, curiously, like most of TypeScript is — in actual fact, they’re one of many few, new options that improve the language.
Enums enable builders to outline a strict set of choices for a variable. For instance:
enum Door { Open, Closed, Ajar // half open, half closed }
Enums default to quantity enums, so the above enum is basically an object with 0
, 1
, and 2
as its key, which we are able to see within the transpiled JavaScript code.
"use strict"; var Door; (perform (Door) { Door[Door["Open"] = 0] = "Open"; Door[Door["Closed"] = 1] = "Closed"; Door[Door["Ajar"] = 2] = "Ajar"; // half open, half closed })(Door || (Door = {})); console.log(Door.FullyOpened);
In TypeScript, you may also use string enums, like so:
enum Door { Open = "open", Closed = "closed", Ajar = "ajar" // half open, half closed }
In case you then used this Door
enum, you could possibly be certain that variables solely used the three choices specified within the enum. So, you couldn’t assign one thing incorrectly by chance or simply create bugs this fashion.
In case you do attempt to use one other variable, it should throw a kind error like this:
enum Door { Open = "open", Closed = "closed", Ajar = "ajar" // half open, half closed } console.log(Door.FulyOpened)
Property 'FullyOpened' doesn't exist on sort 'typeof Door'.
Why do we have to lengthen an enum?
Extension is among the 4 pillars of object orientation and is a language function current in TypeScript. Extending an enum permits you to primarily copy a variable definition and add one thing further to it.
So, for instance, you is perhaps making an attempt to do one thing like this:
enum Door { Open = "open", Closed = "closed", Ajar = "ajar" // half open, half closed } enum DoorFrame extends Door { // This is not going to work! Lacking = "noDoor" } console.log(DoorFrame.Lacking)
We might then add further properties into an enum, and even merge two enums collectively, to nonetheless get strict typing on our enum whereas additionally with the ability to change them after they’ve been outlined.
However discover that the above code snippet doesn’t work! It fails to transpile and throws 4 completely different errors.
Are you able to lengthen enums?
The quick reply isn’t any, you’ll be able to’t lengthen enums as a result of TypeScript provides no language function to increase them. Nonetheless, there are workarounds you’ll be able to make the most of to realize what inheritance would.
Kind intersection in TypeScript
enum Door { Open = "open", Closed = "closed", Ajar = "ajar" // half open, half closed } enum DoorFrame { Lacking = "noDoor" } sort DoorState = Door | DoorFrame;
Within the above code block, we used an intersection sort. The intersection acts like an “or,” which merely signifies that the DoorState
sort will both be of sort Door
or of sort DoorFrame
.
This now means DoorState
can use both of the variables from the 2 enums interchangeably.
Unfold syntax
Now we have seen within the transpiled code earlier that an enum turns into a JavaScript object, with the keys and values that your enum specifies.
In TypeScript, we might write purely JavaScript if we needed to. The truth is, that is one massive energy of TypeScript. You can, for instance, rename all of your file.js
to file.ts
and switch off the compiler checks in your code. So long as you run the compile/transpile steps, every part would work nice, with zero code adjustments.
We are able to make use of this by realizing that when our enum turns into JavaScript, it will likely be a JavaScript object literal and use the unfold syntax, like beneath:
enum Transfer { LEFT = 'Left', RIGHT = 'Proper', FORWARD = 'Ahead', BACKWARD = 'Backward' } const myMove = { ...Transfer, JUMP: 'Bounce' }
This resolution has been described secondly, although, because it isn’t nearly as good of an answer because the intersection sort as a result of it isn’t as sturdy as our first resolution. It is because the “composition” of your enum is happening at run time, whereas once we use sort intersection, sort checking can happen at compile/transpile time, not runtime.
TypeScript enum greatest practices
Now we have mentioned how we are able to lengthen enums in Typescript, however enums aren’t a magic bullet for use to repair all issues. Enums, when used incorrectly, could make your code readability, scalability, and maintainability worse, slightly than enhance your code.
So, let’s cowl some greatest practices and customary patterns to make use of when working with enums in TypeScript.
1. Keep away from heterogenous enums
I’ve defined how we are able to have string enums like this:
enum Seasons { Summer season = "Summer season", Winter = "Winter", Spring = "Spring", Fall = "Fall" }
Alongside additionally having numerical enums like this:
enum Determination { Sure, No }
However, there’s a third sort of enum, which you might not be conscious of, known as a heterogenous enum. That is the place you should utilize a string and numerical enums in the identical enum.
An instance from the docs is that this:
enum BooleanLikeHeterogeneousEnum { No = 0, Sure = "YES", }
It’s vital to notice that even the docs discourage this follow, as on this occasion, utilizing this technique signifies you doubtless must:
- Rethink the connection between these two variables
- Create two separate enums
- Make them each conform to 1 knowledge sort
2. The “enums as configuration” anti-pattern
Typically code performance may be compelled to stick to an enum possibility, which may shortly flip into an antipattern.
Right here’s an instance:
enum Operators { Add, Subtract } perform calculate(op: Operators, firstNumber: quantity, secondNumber: quantity) { change(op) { case Operators.Add: return firstNumber + secondNumber case Operators.Subtract: return firstNumber - secondNumber } }
The above code seems pretty easy and protected, as a result of our instance is, certainly, easy and protected.
However in giant codebases, whenever you strictly tie implementation particulars to enum sorts like this, you’ll be able to trigger a number of points:
- You create two sources of reality (each the enum and the perform should be up to date if the enum adjustments)
- This sample goes to unfold metadata across the code
- The code block is now not generic
If it’s worthwhile to do one thing just like the above, an easier (and extra condensed) sample might appear to be this.
const Operators = { Add: { id: 0, apply(firstNumber: quantity, secondNumber: quantity) { return firstNumber + secondNumber } }, Subtract: { id: 1, apply(firstNumber: quantity, secondNumber: quantity) { return firstNumber - secondNumber } } }
You may learn extra about this sample right here or right here.
3. The kinds of knowledge that enums greatest signify
There’s a manner of usually grouping collectively various kinds of knowledge utilized in code: discrete variables or steady variables.
Discrete variables are knowledge which have areas between their representations, and have only some representations. Listed here are a number of examples:
- Days of the week
- Mon
- Tue
- Wed
- Thur
- Fri
- Sat
- Solar
- Seasons
- Summer season
- Winter
- Spring
- Fall
Discrete knowledge is an effective candidate to be positioned inside an enum, and it will possibly assist code readability and reuse. Steady knowledge refers to knowledge with out gaps that fall right into a steady sequence, like numbers. These may be completely different relying on their measurement:
- Somebody’s weight
- The velocity of a automobile
Discrete knowledge is an effective candidate for knowledge, and it may be utilized in an enum, whereas steady knowledge shouldn’t be utilized in an enum. Are you able to think about an enum for age?
enum Age { Zero, One, Two, Three, 4, 5, Six }
This isn’t a superb candidate to be positioned in an enum as a result of it should should be constantly up to date and amended, resulting in a upkeep nightmare.
It is best to solely look so as to add discrete, extremely secure kinds of knowledge inside an enum.
Conclusion
I hope this text has been helpful so that you higher perceive what enums are, the issues they resolve, the use instances for merging two enums, and the way you would possibly obtain it! Glad hacking.
Writing loads of TypeScript? Watch the recording of our latest TypeScript meetup to find out about writing extra readable code.
TypeScript brings sort security to JavaScript. There generally is a rigidity between sort security and readable code. Watch the recording for a deep dive on some new options of TypeScript 4.4.