DEV Community

Cover image for Typescript: Enums
Jatin Sharma
Jatin Sharma

Posted on

Typescript: Enums

In this article, you'll learn about what enums are and how you can use them in your projects. Enums, short for Enumerated Types.

This is going to be a full series of typescript where you will learn from basic topics like string, boolean to more complex like Type Aliases, enums, Interface, generics, and etc.

Table of Contents

Enums

Enums are one of the few features TypeScript has which is not a type-level extension of JavaScript.

Enums allow a developer to define a set of named constants. Using enums can make it easier to document intent, or create a set of distinct cases. TypeScript provides both numeric and string-based enums.

Numeric enums

We will first take a look at Numeric enums and how we can create them. An enum can be defined using the enum keyword.

enum Direction  {
    Up, 
    Down, 
    Left, 
    Right,
}
Enter fullscreen mode Exit fullscreen mode

Above, we have a numeric enum where Up is initialized with 0. All of the following members are auto-incremented from that point on. In other words, Direction.Up has the value 0, Down has 1, Left has 2, and Right has 3.

In the Numeric enums, the values are in the incremented order as explained above. You can manipulate these values as you want. Let’s take a few examples of that:

// Up = 1, Down = 2, Left = 3, Right = 4
enum Direction  {
    Up = 1, 
    Down, 
    Left, 
    Right,
}

// Up = 1, Down = 5, Left = 6, Right = 7
enum Direction  {
    Up, 
    Down = 5, 
    Left, 
    Right,
}

// Up = 10, Down = 11, Left = 14, Right = 15
enum Direction  {
    Up = 10, 
    Down, 
    Left = 14, 
    Right,
}
Enter fullscreen mode Exit fullscreen mode

In the above code example, I have updated the values and shown you what will be the value of the others members.

String enums

String enums are a similar concept. In a string enum, each member has to be constant-initialized with a string literal, or with another string enum member.

enum Direction {
  Up = "UP",
  Down = "DOWN",
  Left = "LEFT",
  Right = "RIGHT",
}
Enter fullscreen mode Exit fullscreen mode

To access any members you can do the following:

console.log(Direction.Up) // output: UP
Enter fullscreen mode Exit fullscreen mode

Heterogeneous enums

enums can be mixed with string and numeric members, but it’s not clear why you would ever want to do so. it’s advised that you don’t do this.

enum ExtraFries {
  No = 0,
  Yes = "YES",
}
Enter fullscreen mode Exit fullscreen mode

If you want to learn more about Enums, consider reading the documentation.

Wrapping up

In this article, I have explained what enums are and how you can use them in your projects. Enums, short for Enumerated Types.

This is a series of Typescript that will help you to learn Typescript from the scratch. If you enjoyed this article, then don't forget to give ❤️ and Bookmark 🏷️for later use and if you have any questions or feedback then don't hesitate to drop them in the comments below. I'll see in the next one.

Connect with me

Top comments (18)

Collapse
 
1canas profile image
Pedro Furlaneto

Nice article bro 🔥🔥

Could you give me an example of when I could use an enum instead of an object, please?

Keep going on the series dude!

Collapse
 
j471n profile image
Jatin Sharma

Objects are re-assignable but you can't assign values to enums types.

enum ExtraFries {
  No = "No",
  Yes = "YES",
}

let v1 = ExtraFries.No;
let v2 = ExtraFries.Yes;

// ❌ Type '"Yes"' is not assignable to type 'ExtraFries
v1 = "Yes";

// ❌ Cannot assign to 'No' because it is a read-only property.
ExtraFries.No = "Nooooo"

// ✅ This will work
v1 = ExtraFries.Yes
Enter fullscreen mode Exit fullscreen mode

But if we use object that it will allows us:

const obj = {
    no: "NO",
    yes:"YES"
}

let v3 = obj.no
v3 = "YES";

obj.no = "Nooooooooooooooo"
// It will allow everything
Enter fullscreen mode Exit fullscreen mode

You can check the playground:
typescriptlang.org/play?#code/PTAE...

Collapse
 
1canas profile image
Pedro Furlaneto

Thanks bro! 🤝

Collapse
 
karfau profile image
Christian Bewernitz • Edited

by appending as const to the value of obj you even get a read-only version of it, which can not be modified at runtime, and where obj.no and obj.yes have a narrowed type of the string literal value!

To even get a type for all the possible values, you can use the following snippet:

type EnumFromDict<T extends ReadonlyRecord<string, string>> = T[keyof T];
Enter fullscreen mode Exit fullscreen mode

of course it might help to have the same casing for both keys and values to simplify your searches.
Putting it all together:

export const YesNo = {
  Yes: 'Yes',
  No: 'No',
} as const;
export type YesNo = EnumFromDict<typeof YesNo>;
Enter fullscreen mode Exit fullscreen mode

(yes, you can export a type and a value with the same name from a module!)

This still allows you to use literal values everywhere and from what I know if as close as you can get to an enum.
If you need to reference the type of one of the keys from the const, you need to use typeof YesNo.Yes. (There are other options but they are longer.)

Hope it helps

Thread Thread
 
1canas profile image
Pedro Furlaneto

Thanks mate! It will helps for sure, I was searching for that way of typing

🤝🤝

Collapse
 
atinypixel profile image
Aziz Kaukawala

Helping a lot! 🫀
Please keep continuing the series mate!

Thank you! 🔥🔥

Collapse
 
j471n profile image
Jatin Sharma

Thanks mate. Definitely.

Collapse
 
briannbates profile image
Brian Bates

Really cool and helpful! Thanks!

Collapse
 
j471n profile image
Jatin Sharma

I am glad you find it useful 😊

Collapse
 
wraith profile image
Jake Lundberg

Great breakdown :) and thank you for sharing that the Heterogeneous enums are a bad idea! Keep up the good work!

Collapse
 
j471n profile image
Jatin Sharma

Thanks mate 😊

Collapse
 
swordheath profile image
Heather Parker

I loved this post series; it's incredible!

Collapse
 
j471n profile image
Jatin Sharma

Thanks Heather.

Collapse
 
eerk profile image
eerk

Since I discovered you can use strings as types I just use the following:

type Direction = "UP" | "LEFT" | "DOWN" | "RIGHT"
let direction : Direction = "boink"  // error :boink is not assignable to direction
let direction : Direction = "UP"      // allowed
Enter fullscreen mode Exit fullscreen mode

I find it actually less confusing than enums?

Collapse
 
dmitryefimenko profile image
Dmitry A. Efimenko

I wish this article didn't get this much positive feedback - or any at all for that matter.
I see comments like "Really cool and helpful! Thanks!". No, it's the opposite of helpful. It's spreading an anti-pattern. Nothing wrong with talking about what Enums are. But if you do that, you should also talk whether Enums should ever be used in TS. And the answer is - in most cases they should not.

TypeScript Enums are an awkward attempt to make Enums from C# or Java work in JS. They have weird edge-cases and should almost never be used. String literals will achieve the result with better ergonomics in most situations. This is the most important thing anybody need to know about JS Enums.

Don't believe me? Just do a quick google search and see smarter people talk about it.

Collapse
 
exotelis profile image
Sebastian Krah

I can just agree. Enums in TypeScript should be avoided. See also @karfau answer for a better approach.

Collapse
 
codeofrelevancy profile image
Code of Relevancy

Great article..

Collapse
 
yoichitrigalot profile image
Yoïchi Trigalot

Such a great series of articles. Although I used type script in some of my projects, it helps me simplify, popularize, and understand better some subtleties.
Great job man! Appreciate 🔥