Have you ever wondered why TypeScript experts recommend avoiding the use of ENUMs? While they may seem like a useful tool for defining a set of con...
For further actions, you may consider blocking this person and/or reporting abuse
This is a rather strange statement considering that typescript always generates more code than you write.
I think he implied: compared to using const.
Ok let check it. I have this code:
What we have:
ConstRoles used 12 times and have 324 characters (27 * 12)
Roles used also 12 times and have 306 (10 * 12 = 120, 120 + 186 enum definition character = 306).
Seems
const enum
occupied more characters thenenum
in this case. Ok may be my example too rude but it reflect my opinion about talks like "for this will be generate more code then for another one" can't will be common it always local and dependece from use case.The article talks compares
Enum and Const
not
Enum and Const enum
Also it talks about
We're not talking about typescript code. We're talking about javascript converted code from typescript. Const has a native type in javascript whilst enum doesn't, so it has to be converted.
Take a look at this (which is the example above in the article):
Playground Link
Even if you copy and paste your code into that playground you can see enum differences with const, also that const enum should be avoid, it's glitchy sometime and bundle size wise it's better to use const. In some case it's just better to use Type, rather than also const itself. Depends on what you're doing, but enum should be avoided.
"We're not talking about typescript code." - I'm also talking about JavaScript and all conslusions in my previous comment also about JavaScript not TypeScript.
"Even if you copy and paste your code into that playground you can see enum differences with const" - ok let's compare it:
and
I see only one difference
Roles
defined withvar
,Roles1
defined asconst
. Constant onRoles1
not guarantee anything actually. I can to do in consoleRoles1.Admin = "writer"
and yes it will be works. Correct way to do constant is makeObject.freeze(Roles1);
after definition of object. Another way isconst RolesAdmin = "admin"; const RolesWriter = "writer";...
."it's glitchy sometime" may be don't use TypeScript at all if it have glitches? :)
They are talking about the JS that is generated by the compilation of TS and not an analogue that is intentionally programmed. The generated code is bigger than what you would actually intentionally make in JS.
Still, I don't think it's that big of a difference. It's not like you are going to use dozens of enums in your code... Most of the time you will use types instead of the string-based enums
It dependence from what standart you select while transpile JS, may be all modern features not be have analogue for it standart.
It dependence what values do you have (in most time from backend) and it can be anything.
Good article!👏
You could also use enums in combination with
interfaces
,types
ofclasses
to encapsulate the behaviour of theenum
, but, to be honest, I don’t really see a usage of anenum
. You have far better solutions which are type safer such as string literals:This adds the benefit of preventing typos because that allow you to match the exact string value that is desired to be used. You have other better solutions as well, but this one should be a good one to replace the usage of an
enum
.sure, but exept when your strings were too lang.
I prefer unions. More portable, you still get auto-complete and they are compiled away from the code into types only, without ever reaching the JavaScript output.
They also support codebase-wide renaming for most but a few edge cases.
type RoleKeys = typeof Roles[keyof typeof Roles]
This line basically generates union from Roles object, still giving you access to "enums-like" syntax:
Roles.Admin
Union types, a.k.a. unions, are types, too. You know, like
Yes of course they are also types.
Great article!
If you write export const enum you won't generate single value.
And it will compile to nothing and in thee code it will have the hard code value
export const enum Enum {
FIRST = 'name'
}
I find it funny that experts recommend not using enums. We would have to see who these experts are, where they recommend not using enums and what they argue about it.
In my humble opinion, and point by point, one can argue against the "disadvantages" that the author of the article exposes:
Enums increase the weight of the build because they produce code. Obviously, because enums are translated into objects when compiling. This is by design and thanks to that you can iterate over the properties of an enum, for example: Object.keys(MyEnum).map(...). Of course replacing them with normal objects is not going to make the build weigh less XDDD.
Numeric enums are not type-safe. Correct, more or less and if you use them wrong (as in the example passing a number instead of using the enum you are defining). At compile time you don't have to write like this if you want TS to validate you (and whoever reads your code doesn't hate you). At runtime this can occur like any TypeScript violation (because it doesn't exist at runtime). If you don't like the quirks of numeric enums, the solution is not to use numeric enums. They have other disadvantages such as each value produces two entries in the compiled code, one for the value and one for the name. This does increase the weight of the build and is susceptible to producing errors when iterating as in the previous point. Could we say that experts recommend not using numeric enums? Maybe, but I wouldn't even dare, because they have their niche.
Valid strings such as "admin" cannot be passed instead of Roles.Admin. Goodness! Thanks to this you can't screw up like in point 2 with the numbers. Source code is clearer and less prone to errors when you are clear about what you are using. If you want to pass strings, don't use enums. If you want to use enums, don't pass strings. Roles.Admin is not the same as "admin".
Regarding the "solution": I think that allowing two ways of writing the same thing complicates the code without providing any advantage. In my opinion (I suppose a non-expert for the author of the article) it is better to use enums for this case and not allow strings.** If you want to use strings, don't use enums. If you want to use enums, don't use strings**. :-)
I like the string Enum approach and I haven't face those issues when trying to use the real string instead of the enum key.
If you need to explicitly pass the string, you can use "as" to force its mapping. It will map perfectly with the string value of your enum.
I know we should avoid using "as", but it's a very unlikely situation (I can't think in a use case to explicitly pass a string if I have the enum keys).
I think the most common use case will be to match data received from the backend (string) with the frontend enum type. But just using "as" will map perfectly.
Based on the example in the article:
And by using enums instead of "objects as const", I don't need to do things like
RoleKeys = typeof Roles[keyof typeof Roles]
just to be able to use it.the down side to doing something like
hasAccess("fish" as Roles)
you are basically saying, trust me TS, I know this is right. which is the danger that the article is warning about.That's the main use case for me too. To map in an enum values that come from backend. But that can also be done with a plain type. I guess I tend to use enums for that because I'm mostly a backend developer so I'm more used to enums than types
Example from "Numeric types usafe" is no longer relevant since TypeScript 5.0
Well, i.e. in the paragraph above, you write how bad it is that the typescript does not check that the value is in the range of the Enum. And here you write how to make it possible for strings, which will eventually lead to the same problems in the future as in the previous example.
May be you share examples in post?
what do you do when someone fat fingers
I found another solution, which looks a bit more elegant to me:
What is the purpose of
enum
existence, then?I assume you meant
hasAccess('admin')
instead ofmove('admin')
?Articles like these are great 👍 very good explanation of the problem and the solution! Many thumbsup 👍👍👍