In TypeScript, there is a feature called Enum
which is not a type-level extension of JavaScript. Enums allow a developer to define a set of named constants.
enum EDirection {
Up = "Up",
Down = "Down",
Left = "Left",
Right = "Right",
}
// Using the enum as a parameter
function walk(dir: EDirection) {}
walk(EDirection.Left);
But, on the other hand, we may not need Enum as TypeScript team says on https://www.typescriptlang.org/docs/handbook/enums.html#objects-vs-enums by using an object with as const
.
const ODirection = {
Up: "Up",
Down: "Down",
Left: "Left",
Right: "Right",
} as const;
type Direction = typeof ODirection[keyof typeof ODirection];
function run(dir: Direction) {}
run(ODirection.Right);
So what's the difference between Enum and Object? I'll discuss the difference in Data Types, Bundle size, and How to use aspects.
Data Types
Enum
TypeScript provides both numeric and string-based enums.
// Numeric Enums
enum UserResponse {
No = 0,
Yes = 1,
}
// String Enums
enum UserResponse {
No = "No",
Yes = "Yes",
}
Constants
While Constants
can cover an object with string and number property values including all data types.
// Number
const PI = 3.14159;
// String
const GREETING = "Hello, World!";
// Boolean
const IS_ACTIVE = true;
// Array
const COLORS = ["red", "green", "blue"];
// Object
const PERSON = {
name: "John",
age: 30
};
// RegExp
const EMAIL_PATTERN = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;
// Null
const NO_VALUE = null;
// Undefined
const UNDEFINED_VALUE = undefined;
// Symbol
const UNIQUE_KEY = Symbol("unique");
Transpiled Size
I used https://babeljs.io/repl to know the size after the code has been transpiled.
Enum
enum Color {
Red = "RED",
Green = "GREEN",
Blue = "BLUE"
}
// Transpiled Result
var Color = /*#__PURE__*/function (Color) {
Color["Red"] = "RED";
Color["Green"] = "GREEN";
Color["Blue"] = "BLUE";
return Color;
}(Color || {});
// Size: 153 Bytes
Constants
const COLOR = {
red: "RED",
green: "GREEN",
blue: "BLUE"
} as const;
// Transpiled Result
const COLOR = {
red: "RED",
green: "GREEN",
blue: "BLUE"
};
// Size: 65 Bytes
How to use
An Enum named EDirection
and an object named ODirection
refer to the same thing as what we talked about earlier.
Enum
walk("Left");
// This shows an error ❌
// (Argument of type '"Left"' is not assignable to parameter of type 'EDirection')
walk(EDirection.Left);
// This works well ✅
Constant
run("Left");
// This works well ✅
run(ODirection.Left);
// This works well ✅
Conclusion
Based on several aspects I've discussed earlier, we can replace Enum with Object. Object has the flexibility for defining various data types, has a smaller transpiled size, and can detect both property values or property access.
So, it's important to remember that not all cool features are the best choice. Always assess the aspects you think important. If a feature doesn't have any negative impact, then you can confidently use it.
Top comments (21)
Great topic choice!
I used to love enums, but once support for
as const
was released, I stopped using them entirely for the exact reasons you laid out here. I never really liked that enums were the one thing in TS that didn't get stripped out during build...instead, it just gets mutated and added to the bundle.Nice explanations! Keep up the great work!
I'm glad to know that!
I found your post about TypeScript Enums really interesting and thought-provoking. It's great to see different perspectives on how to approach common programming tasks.
While I'm a fan of TypeScript Enums for the type safety they provide, your article makes some valid points about alternative ways to handle certain situations. It's crucial for developers to be aware of different approaches and choose the one that best fits the specific needs of their project.
What I appreciate most about your post is that it encourages a healthy discussion about TypeScript's strengths and potential alternatives, which can help us all become better developers. Thanks for sharing your insights and sparking this conversation!
I believe the best approach often depends on the context of the project and the development team's preferences. Keep the great articles coming, and I'm looking forward to more thought-provoking discussions in the future!
Yeah, it does. Sometimes speed is prioritized over performance in a project...
Anyway, thanks for the kind feedback!
Seems introspective! Gonna try this approach!
Thanks Muhammad!
Cool!
We use
as const
since it can infer the property values following typescriptlang.org/docs/handbook/e....Speaking of
Object.freeze
, I've tried it and the result is it couldn't infer the property values. Maybe, can you give the example?oh it doesn't infer?, im sorry didn't knew I was just guessing.
No, it doesn't...
I'm avoiding TypeScript enums with all cost. I prefer to use unions instead
This way, TypeScript doesn't need to generate extra hidden code. Unions are also compatible with JavaScript type annotations proposal but enums are not.
Yeah, ultimately, the best approach is to go back to the basics.
Anyway, wow JS will be able to accept type annotations by itself. It's great news!
Thanks Muhammad for this nice explanations !
Using TypeORM in a CRUD app builder, do you think that this preference for const over enum should also apply to databases or the concept of Enum is getting to the developer precious documentation in his development experience which can not really be mesurable ?
It really gives me food for thought !
Personally, I've never tried TypeORM and CASE. But, if it needs to transpile the source code, I suggest you to replace Enum. Otherwise, using Enum is not a problem.
Anyway, you can do you own research on the execution time to check whether Enum can increase the execution time or not.
What does the
as const
do? What if I were to remove it?Here is the difference
Nice article... I've created a small snippet to create an enum only by the provided strings
stackblitz.com/edit/js-kngxa2?file...
Yeah, it can be an option for someone who is lazy enough to define the object with
as const
. My feedback is don't forget to support TypeScript.By the way, it's good!.
With TypeScript, It looks like simple expression and to understand easily
Yeah, it does
did you forget number enums? not having to provide a index is a huge bonus imo, also calling a function with a string isnt really easy to refactor later on