The concept of enumerables is quite simple: an item that can represent a finite number of different things. However, the implementation in language...
For further actions, you may consider blocking this person and/or reporting abuse
I always use const objects instead of enums
In ts how do you add the enum to the declaration?
Like this? Or is there a better way?
You could use
const enumswhich are removed during compilation. For example, this code:compiles to:
Playground
So the enum value (0,1,2...) is inlined into the code during compilation.
However, I avoid enums completely because I don't see a benefit in using enums vs. plain objects defined with
as const:Sure, it's more verbose, but since these are normal javascript object, I can easily transform them in other shapes and they also work really well in types and type constraints. Here is some more background on this: TypeScript: Objects vs Enums
const enums are fine if your code is self-contained, but they are certainly not portable.
You could extract the key and value types:
Alternatively, you could create some generic type helpers:
I agree. TS doesn't provide enums in a way that aligns with other languages. A
constobject comes closer. You can also define a utility type as a list of constants, e g ,type Color = 'red' | 'yellow' | 'green';I'd honestly not looked at what it compiled to, I'd always imagined it was something like this.
Which feels a bit more natural to me.
You won't need to freeze the object if you assert that it is read only on type level.
Still, the unnecessary level of complexity irks me. Even worse, those types are not even portable. If you re-export them, they may get loaded from two different locations and stop being compatible with one another, even though they are the same type.
The freezing is probably just to prevent modification at runtime instead of treating it as a normal variable, with object keys that could be mutated.
They could also unfreeze the object. If they already violate the types, why would they stop there?
This is true for enums by default in TypeScript, but I typically opt for const enums instead.
The good guy Matt Pocock talked about this. The best way yet is to do
notice the
as constpart, which translates toObject.freeze(). The type is very convenient, you could create a generic type to abstract this a little bit and this "enum" is even a little bit more flexible than Typescript's enums. I've been using this instead of enums for the last 6-9 months now, I'll never use enums again until they're standardized in JSAm I the only one who finds this self proclaimed TypeScript expert insufferable? Especially when he talks confidently about stuff he has very little or no practical knowledge what so ever.
If there is something we can all agree it’s that the 2 most important qualities of good code are: 1. it does exactly what it’s supposed to do and 2. it’s easy to read and understand by anyone with basic or even no understanding of the subject.
Your example is the exact opposite of these 2 principles. Might be something you want to consider before blindly trusting “tech influencers”
I wouldn't call Matt a self-proclaimed TypeScript expert, because that would just be an ad hominem that would reflect badly on me rather than on him.
I think good code is a bit more nuanced: the attributes that qualify good code in my understanding are functionality, maintainability and removability. So it has to work, needs to be maintained (which means it is written for humans and represents the least possible complexity required) and has the weakest possible coupling to the rest of the code it is intended to be used with.
Let's look at Matt's example. Does it work? Certainly. Is it written for humans to read and maintain? Mostly. The const assertion and the type are written to satiate TS - but they increase the maintainability. Does it represent the least possible complexity required? I would argue that my solution is slightly less complex, but that's only by a certain margin, so while I would not give him full marks, he still gets a passing grade from me. Has it the weakest possible coupling? The object can easily be replaced by any other objects; however, the identifiers still leak into the code and therefore remain coupled. I would fail him on that one, but two out of three isn't too bad at the end of the day.
So I wouldn't say it is the exact opposite of the best possible solution, because that's what TS enums are at the moment.
It does look like you enjoy writing complex things, I will give you that. Your explanation why this is a reasonable solution is almost as confusing as the original suggestion. I can give you A for effort, but the rest still makes no sense.
In the real world it's hard to justify the use of 2 statements (object definition and type inference) to solve only half of the problem enums are designed for. I mean it's in the name, enumerable... How is the object or the type enumerable? Oh yeah, you can write
Object.keys()to achieve that. Congrats now you have 3 statements to solve the problem and let's not talk about dependencies between them and how you need to manage 3 separate references in your codebase. Fascinating! You were able to extrapolate a single simple solution into a 3 dimensional problem. Wow. I guess things like performance and scalability (multiplying every enum by 3) are out of scope. That's how you reach the point in the conversation where you need to ask the question "What are we actually trying to do?" and hopefully come to realization that maybe just maybe you need to get out of the rabbit hole.You seem to confuse enumerable with iterable. The latter is not necessarily a property of enums, even though it is nice to have it.
Also, you seem to have misinterpreted my intention. I had hoped tsc could be made to restore the original enum from the type information so it could be made portable beyond just being exported as multiple constants.
I am aware that this is still not an ideal solution, but it is currently the best we can do without creating a new TC39 proposal that does away with the extra complexity.
Lastly, your opinionated and fallacy-laden discussion style detracts from your criticism.
@cmacu I agree you're creating more references in the code with Matt's suggestion, but that still is the worst thing it's happening for me, nothing worse. Moreover, you're just creating a simple and friendly JS literal object in the transpiled code, as the type goes away, while the native "enum" approach creates some ugly IIFE with double the declared properties in the enum instead (check TypeScript Playground's compiled JS panel on the right).
I think we can all agree that native enums would be much better and solve the problem of having a somewhat weird syntax with
as constlike this, but for now that is the "most performant way" and also the most JS-friendly way I'd say.Marginally, enums declared like this both provide the benefit of typing, avoiding literal values in code but also you can use its type in a little more forgiving way. Take this for example
Notice that I can call
selectLanguage()with both a literal value (maybe coming from external sources like an HTTP request or database) and with the pseudo-enum without being forced to the use real enum, when using the enum as a type. For me, it's a nice thing to haveMy method is lengthy, but also arguably the most powerful:
Note: in all of my code bases I do not use TypeScript's built in enums for aforementioned issues, and other minor implementation inconsistencies. The above method is more powerful as it allows for inline enum variant selections (instead of
EnumImplementation.Rustyou can just put0, and so on) and doesn't feature any other hidden traps during runtime.I discourage the use of enums whenever possible for a few reasons, them being unnecessary as the primary one. Typescript really doesn't need them and depending on the "guarantees" you can make about a code base (immutability etc.) something like defining an object as const and then inferring the types from that is a lot more practical
Oh yes. I found out my favourite optimization (from C), that makes the code more effective by replacing strings with numbers (number comparison is always faster than eg. string), is not an optimization at all in Typescript.
So I use constants.
Hi Alex Lohr,
Top, very nice and helpful !
Thanks for sharing.
I always thought they were syntax sugar for constants. I guess I'll use more true constants then.
Typescript enums are deprecated and should not be used anymore.
Const objects are the way to go in typescript/javascript.
If you need 1 or more value mappings you use:
Typescript enums aren’t deprecated. Can you share me an official statement from typescript on it? They are only discouraged for use by one side of the community, there are lovers for enums too.
Even on the official typescript website it lists problems, pitfalls using enums (instead of using const objects)
typescriptlang.org/docs/handbook/e...
and it does not even touch frameworks, babel, and other build tools that all had (or still have) problems with typescript enums.
If you run your code everywhere besides your own dev machine you have to care about how it gets build, deployed and run by the user.
If you have 2 possible solutions, one of which is completely problem free and the over is fraught by countless pitfalls -> it may not be officially sunsetted, but is a bad choice to make in any case.
Even official maintainers/creators of typescript regret the creation of enums.
Hence my TLDR summary: enums are deprecated
On the official docs it only lists pitfalls with const enums, which do not apply to enums generally. And even the const enum pitfalls, as it clearly says, only apply if you're emitting or consuming d.ts files.
What problems with frameworks or build tools are you referring to exactly? Personally in years of working with typescript and many different frameworks, and some pretty wild build pipelines, I don't think I recall ever having any issues related to enums specifically.
Sure but what does this have to do with ... enums? How would enums even have any effect on how your code gets deployed and ran by the user
Again, what "countless pitfalls" are you talking about...
Citation needed
Well you're wrong though. They're not deprecated.
It may have problems, yes, but as far as I know it's not deprecated. And officially deprecated is the only kind of deprecated. You could say it's a bad practice to use it in your point of view, but you can't say it's deprecated. Deprecation is a way to say "this should be done differently and may be removed in future versions". I don't see that movement from Typescript.
Why not using string enums ?
Because it makes no difference whatsoever in relation to the aforementioned shortcomings.
I see the enum type in Typescript as a helper to prevent Typos as the autocomplete will tell you what constante are available; enum become types in Typescript, meaning they are helpful to narrow down the possible values for a variable.
For instance, the snippet below showcases a way to make them useful:
const request = (url: string, method: "POST" | "GET) => {// ...
};
becomes
enum Method {GET = "GET",
POST = "POST"
}
const request = (url: string, method: Method) => {
// ...
};
--> now, the code above ensures not other value of the enum values are possible for the request method.
You're right in that the transpiled code looks ugly. In fact, there is a way to make the transpiled version better by using const enum. But the latter has performance side-effect. Overall, I wanted to add this comment so that we can validate a positive way that Typescript provides to use them
A union type will also provide autocomplete. Re-exporting enums can cause big issues. Const enums not only has performance side effects, but also affects portability of the code.
much appreciated, I will bear in mind the portability issue. Not something I have come across, and it is very insightful.
I understand your frustration with TypeScript enums. The concept of enumerables is straightforward, but the implementation can vary significantly across languages. TypeScript's transpilation to JavaScript does result in more verbose code compared to some other languages like Rust and F#.
Consider the example you provided:
enum EnumImplementations {
Rust,
FSharp,
TypeScript,
}
console.log(EnumImplementations.TypeScript);
Transpilation to JavaScript results in:
var EnumImplementations;
(function (EnumImplementations) {
EnumImplementations[EnumImplementations["Rust"] = 0] = "Rust";
EnumImplementations[EnumImplementations["FSharp"] = 1] = "FSharp";
EnumImplementations[EnumImplementations["TypeScript"] = 2] = "TypeScript";
})(EnumImplementations || (EnumImplementations = {}));
console.log(EnumImplementations.TypeScript);
This is quite a bit of code just to map three numbers to their names, and it does make tree shaking less effective.
A more concise and tree-shakable approach could look like this:
javascript
/**
console.log(_EnumImplementation_TypeScript);
This approach is not only more concise but also more readable. It would be great if TypeScript could offer a more optimized way to handle enums in the future.
For anyone interested in exploring more about TypeScript and its intricacies, I highly recommend checking out Codeflee, which provides excellent resources and tutorials on web development and TypeScript.
What's your take on this? Have you found any workarounds or alternatives that work better in your projects?
Why not just use const enums which do compile away into literals?
typescriptlang.org/docs/handbook/e...