DEV Community

Cover image for TypeScript Best Practices — Using Enums
Stephen Gbolagade
Stephen Gbolagade

Posted on

TypeScript Best Practices — Using Enums

TypeScript is not just about validation, It's also about structure and today, let's talk about using ENUMS to save your team unnecessary hours of debugging.

In enterprise software development, we often use Typescript to ensure our data is consistent.

But aside from using any to deceive ourselves (not the machine), we also ignore the importance of ENUMS.

Here is a scenario:

Your company is developing a food delivery software and you have 3 type of users who can sign up as demonstrated in the snippet below.

Someone in your team used Vendor, another person used vendor, you used VENDOR

That's a simple bug that can waste hours of productivity.

Solution:

Use ENUM to define the structure of your user Role. ENUM is readonly and very strict, it'll get your team members in order.

Code snippets

// Do ✅️
enum Role {
  Vendor = "VENDOR",
  Customer = "CUSTOMER",
  Rider = "RIDER"
}

const userRole: Role = Role.Admin;

// Don't ❌️
const userRole = "VENDOR"; // Very badd

// learn moteat www.stephengade.com

Enter fullscreen mode Exit fullscreen mode

Top comments (31)

Collapse
 
tomosterlund profile image
Tom Österlund

I like using enums too for objects.

TS-team however, recommends we use objects instead, like:

Object.freeze({
 Vendor: "VENDOR",
  Customer: "CUSTOMER",
  Rider: "RIDER"
})
Enter fullscreen mode Exit fullscreen mode

enums have some type-safety issues: dev.to/ivanzm123/dont-use-enums-in...

Collapse
 
stephengade profile image
Stephen Gbolagade

This is a good take

Collapse
 
mordechaim profile image
Mordechai Meisels • Edited

No, use string unions instead.

Enums introduce a runtime construct and typescript should only be a compile-time tool.

Unions gives you all the type safety and -- for libraries -- works for JavaScript (i.e. non typescript) projects flawlessly.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

I get what you mean, but what you say is wrong: It is a compile-time tool, or better stated, a transpilation tool since JS is not compiled by today's tools. Today's tools transpile, bundle and minify, but don't compile.

What you meant to say is that TS should not "write extra code", or at least this is what I think you meant. If I'm correct, that's also wrong: TypeScript, depending on the target version of ECMAScript, will generate code accordingly. By design, TS is meant to support as much as possible all the newest syntax ahead of time, and is ready to shim on the fly.

Finally, there is no absolute "best" enum. String unions are nice, but numeric enums are great:

  • A numeric enum only consume a fixed number of bytes regardless of its value, while a string consumes bytes depending on the string length.
  • A numeric enum can be used as a set of Boolean values when its values are single bits, and both read and write operations are O(1).
Collapse
 
mattchowski profile image
Mateusz Wojciechowski

Not everything needs to be measured in bytes and performance, especially in JS where you're not building space ships or medical equipment.

Dev experience is also really important and enums give you none. String unions are perfectly fine and superior in most cases due to their simplicity and "logicalness" for lack of a better word.

Thread Thread
 
webjose profile image
José Pablo Ramírez Vargas

Not everything needs to be measured in bytes and performance, especially in JS where you're not building space ships or medical equipment.

Apologies, but I call them as I see them: This mentality brings projects to the ground. People who say this most likely say it because they can't optimize, they can't have performance in mind while writing code. These people need people like me doing their code reviews.

Yes, string unions are simpler, but they aren't superior in any way I can think of right now. Do you have a concrete example? This part got me curious. Let's forget about bitmasked enums for a moment and simply talk string unions vs. numerical enums. Do you have a concrete case where the string union shines vs. a numerical enum?

Thread Thread
 
mattchowski profile image
Mateusz Wojciechowski

The fact that they're simpler is superior. Just because a developer uses string unions it doesn't mean they don't have optimized or performant code. Writing performant code doesn't always equal to a successful developer. A successful developer must also keep in mind the developer experience and must be efficient, there is a balance between efficiency and performance, if you find that balance then you're good.

I'm not gonna spend 2 hours fixing enum types in complex cases and looking for workarounds when I can just use string unions and call it a day, when the outcome is the same.

If choosing between an enum or a string union has impact on your app performance then youve chosen the TS is the wrong language for your application.

Thread Thread
 
webjose profile image
José Pablo Ramírez Vargas

Ok, fair point. Just a reminder, as it seems to may have been lost: I am not saying to always go for numeric enums. I just say that it is hard for me to say string unions are the clear superior.

You are correct in that there should be balance, and your explanation makes complete sense. In the point I continue to disagree is that simplicity alone is sufficient to make them superior. For us to continue debating on this topic, we would have to define the term superiority. If you would like to, define it. Otherwise, we can call it a matter of opinion since our concept of "superiority" probably varies.

Collapse
 
sc7639 profile image
Scott Crossan

Came here to say this

Collapse
 
dmitryefimenko profile image
Dmitry A. Efimenko

Enums in typescript are not great. Most of the time when you're thinking about using enums, try using string literal instead:

type Role = 'VENDOR' | 'CUSTOMER' | `RIDER`;
Enter fullscreen mode Exit fullscreen mode

This provides same level of type safety, same intellisence, but less verbose and easier to use

Collapse
 
michael_mannseicher_836f6 profile image
Michael Mannseicher • Edited

I would do it so

const ROLES = <const>['VENDOR','CUSTOMER' ,'RIDER'];
type Role = typeof ROLES[number];
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ironblossom profile image
Ishtiaq Mahmood Amin

Enums are horrible, considering the alternatives that typescript provides

Collapse
 
lexlohr profile image
Alex Lohr

As my previous discussion on the topic shows, enums have their uses and limitations and neither of their currently available replacements is very satisfying. Let's hope that there will be a native enums proposal to TC39 that fixes these issues.

Collapse
 
theoephraim profile image
Theo Ephraim • Edited

Aside from the other issues mentioned, it's often very useful to use an object to store additional metadata that may be needed when using the options. You can use keyof typeof to extract the keys into a type (string union) to be used throughout your code.

For example:

const ANIMAL_DATA = Object.freeze({
  dog: { scientificName: 'Canis lupus familiaris' },
  cat: { scientificName: 'Felis catus' },
});

export type AnimalsEnum = keyof typeof ANIMAL_DATA; // 'dog' | 'cat'
Enter fullscreen mode Exit fullscreen mode
Collapse
 
aloisseckar profile image
Alois Sečkár

Let's talk about NOT using enums in TS
wordman.dev/blog/typescript-enums

Collapse
 
juniourrau profile image
Ravin Rau • Edited

I used to use enum last time, but there were some issues that I faced.

  • increase in the size of the output
  • no proper type safety for string enums

Since then have been using plain object

const Role = {
    VENDOR: "Vendor",
    CUSTOMER: "Customer",
    RIDER: "Rider"
};

// Usage
console.log(Role. RIDER); // Output: Rider
Enter fullscreen mode Exit fullscreen mode
Collapse
 
standiki profile image
Stanley Diki

I'm yet to start using TS for projects but I'm excited to read blog posts around it. This is a great content too. Here's my observation: You are trying to access the key "Admin" but it's not defined in your data structure, won't this confused beginners like me? ☺

Collapse
 
stephengade profile image
Stephen Gbolagade

Oh no...

That was a typo.

It was meant to show how to access the value in the enum object.

E.g

Role.Vendor // VENDOR
Enter fullscreen mode Exit fullscreen mode
Collapse
 
standiki profile image
Stanley Diki

Okay, thank you.

Collapse
 
guilherme_taffarelbergam profile image
Guilherme Taffarel Bergamin

Sometimes it's better to use Types for this kind of stuff because enums generate a lot of unnecessary transpired code (not a big issue if you don't have too many, tho) and because types will more easily resonate with people still using strings for this kind of stuff. It's still forcing everyone to use the correct string too.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.