-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
String Enum Initializer #16464
Comments
like this? enum Action: string {
LOAD_PROFILE,
ADD_TASK,
REMOVE_TASK,
} |
That would be perfect! |
This would be super great - any updates on this? |
Yep, this would be a really great addition. See this comment on the original pull request which brought string enums to Typescript. Also mentioned in that thread was the syntax of enum<string> TaskIds {
TASK_RESIZE_IMAGE,
TASK_ADD_PROFILE_PIC,
TASK_DELETE_USER,
} |
yup, I'm about this |
Hey, can we get an update on this? TypeScript 2.9 just came out and honestly it's a little frustrating that we've gone 4 minor releases without any progress reported to this ticket... |
The status on this is the same as it was before |
@RyanCavanaugh What additional Feedback are you looking for (referencing 'Awaiting More Feedback')? |
This label means we'd like to hear from more people who would be helped by this feature, understand their use cases, and possibly contrast with other proposals that might solve the problem in a simpler way (or solve many other problems at once). |
@RyanCavanaugh This is pretty much as simple as its gonna get. We'd just like a way to define string enums without having to repeat everything. I'm not sure what other feedback you require to push through a new feature? Is there just perhaps not enough activity pushing for this? I think the team should maybe weigh in a bit on what they think on the current proposal, and if there are issues we can move on from there. I do foresee a slight issue with what I wrote earlier in the thread:
This won't interact nicely with the current way string enums work, and I'm sure whichever method is chosen it would have to be backwards compatible.
Also, it seems like because of the way its currently implemented that using the But would be nice if the team could weigh in on a way they might envision this as well. |
We're always looking at things holistically. There are over 1,000 open suggestions and it would be a complete disaster to just do all of them; features need to more than pay for themselves in terms of new complexity vs value added. We have to consider questions like:
The bar is much higher than you probably think it is - once something goes into the language, we can't take it out, and everything that exists is something that future TS learners will need to understand. Features at the language level need to feel like "the thing we've been missing all along", not "this would be nice". |
I want to emphasize that I understand and agree with everything you're saying; I don't expect TypeScript to change at the whim of a few users, however I think some of your thinking is overly dismissive. For example, you say that there is "no strong precedent from other languages implying a need," but I would argue that this is inherent to the concept of an enum. Having to define each state of the enum twice, and potentially introducing conflicts where two enum values correspond to the same string, flies in the face of an enum's existential purpose. From that perspective, this isn't just annoying; it's a fundamental flaw in the initial implementation. Once again, I completely understand the challenge of maintaining a language used by thousands in a scalable way, but please remember that we're all here because we love TypeScript and we should be working towards the best solution together. Speaking of which, you say that, "'Convert numeric enum to string enum' refactoring would be trivial to write; we should consider doing that instead" -- but I'm not 100% sure what you mean by that. Is this something we can do in our own codebases? Do you mean just adding a post-transpile hook that changes all the enum values to strings? Thank you again for all you do. |
@thomascmost what's your use-case? |
@icholy I like using string enums to define my action sets for NGRX/Redux features |
@thomascmost why don't you use regular enums? |
Regular enums throw a type error because Redux actions expect a string |
Interesting... maybe I'm thinking of NGRX, or I'm otherwise misinformed. I'll give it another shot |
@thomascmost looks like NGRX does expect a string, but I don't see why that couldn't be extended to |
Okay, but then I think there's another problem: If I have an
...in this case, wouldn't my reducers misfire for both MAKE_USER_MANAGER and RSVP_TO_OCCURRENCE_REQUEST, since they both transpile to a value of 0? |
I can definitely see the problem, there. String enums afford the opportunity for unique values while giving us that enum intellisense we all want. My use case for this would clean up a fairly large enum of localization keys. https://github.com/yamdbf/core/blob/master/src/localization/BaseStrings.ts Granted, I generate this enum via a runtime script to prevent me from forgetting to add any new strings I may have added so it's no hassle on my part to maintain, but it would definitely look cleaner, and make it less of a hassle if I were to add any new keys manually. |
For redux, having string types is valuable because it makes it easier to debug from logs. In an app with over a hundred actions, looking at an action with type |
My counter proposal would be to add an additional fromString method to the generated enum, e.g.
|
An alternative would be to streamline string based enum literals with the standard literals plus a fromString method, e.g.
|
I would like to follow up on my previous comment with a concrete example: This: enum September {
Earth,
Wind,
Fire,
}
enum Elements {
Hydrogen,
Helium,
Oxygen
}
console.log(September.Earth === Elements.Hydrogen); ...has a nice little TypeScript error that says:
...but it logs The TypeScript error, while it would presumably prevent compilation, is actually incorrect. Someone who was playing fast and loose with casting might run into issues, and the Redux problem is illustrated clearly. Earlier, I said to @RyanCavanaugh :
...and while this is in some sense a separate issue I would argue it's related, especially for the use-case I conveyed to @icholy EDIT |
@thomasmost The problem with this is that during runtime, all type information has been erased except for tests of instanceof and similar such mechanisms using for example reflect-metadata. And, also given the fact that TS will impose static type checking on the enum only, it is hard to figure out of what type the enum actually is. In the past, others and I have come up with a more type safe solution, however, this will require additional runtime overhead and I am not sure whether the TS team is willing to introduce a base enum class from which the custom enum is then derived from, making all literals instances of that class. That being said, such an approach would also allow for custom, both static and dynamic methods, and constructors alike, very similar to the one we can see in Java, or maybe even C#. Have a look at for example https://github.com/vibejs/enumjs/blob/master/src/lib/http/EHttpStatus.coffee. Also see http://2ality.com/2016/01/enumify.html. I think that my approach is actually better, however, it requires translation to typescript and one cannot use the reserved keyword enum when declaring such enums. |
@silkentrance This is cool -- I quite like leveraging Thank you for the background/context. I understand that one advantage of TypeScript's enum implementation is runtime performance since they get compiled down to pure strings or numbers. Essentially, I just wanted to make the assertion that adding support for Edit One can even conceive of a world where |
Still would really love to see this handled better by Typescript. Not only because it is "sugar" but because it can help prevent data errors (which with enums can get pretty messy quickly). For example:
Firstly, if I miss-typed an enum value, like I did Now because the enum name is not tied to the value, the chances of me seeing this mistake are probably not high - until some actual data would have made use of the incorrect value (and this error would most likely happen outside of my current Typescript program and local tests - which is why its a more critical problem in my eyes). Secondly - if I refactor one of them in my IDE (Webstorm- though I'm sure it'll be similar in others), we can end up with enums like so:
Which is completely wrong - as they should both be renamed to Basically these problems stem from Typescript not giving us a nice native way of defining string enums and being strict about tying those values together. There should be a way to do so and get all the great Typescript safety that comes with that. |
At the risk of pointing out the obvious, the current way of doing string enums also introduces quite a bit of line noise. Given that types are more likely than other sections of the code to act as documentation, there is definitely a penalty there. |
+1. Insofar as string enums are useful at all (readability in logs and on the wire), their concise definition is also important. Forcing people to enter the reserved value twice is the opposite of basic DRY. |
Does it available to accepting pr whatever sugar or refactor? |
This would be really useful for ambient enums. In my case the code running in the cloud injects an enum like object with string values.
There is no way for me to say that the enum contains string values, it is automatically a number and I get type errors when comparing it to a string. This syntax would be really useful in this case
|
Hi, Could I make a suggestion, I think it's useful. 👇 Desired syntax: enum Grades {
SILVER,
Gold,
pt,
keys,
}
console.log(Grades.SILVER) // 0
console.log(Grades[0]) // 'SILVER'
console.log(Grades.keys) // 3
console.log(Grades.keys()) // ['SILVER', 'Gold', 'pt', 'keys']
console.log(Grades.values()) // [0, 1, 2, 3]
console.log(Grades.map()) // { SILVER: 0, Gold: 1, pt: 2, keys: 3, '0': 'SILVER', ... '3': 'keys' } Keep present syntax and add new methods of String Enum: enum Grades: string {
SILVER,
Gold,
pt,
keys,
}
console.log(Grades.SILVER) // 'SILVER'
console.log(Grades.keys) // 'keys'
console.log(Grades.keys()) // ['SILVER', 'Gold', 'pt', 'keys']
console.log(Grades.values()) // ['SILVER', 'Gold', 'pt', 'keys']
console.log(Grades.map()) // { SILVER: 'SILVER', Gold: 'Gold', pt: 'pt', keys: 'keys' } Mixed: enum Grades: string {
SILVER = 2,
Gold,
pt = 'platinum',
keys,
}
console.log(Grades.SILVER) // 2
console.log(Grades[2]) // 'SILVER'
console.log(Grades.keys) // 'keys'
console.log(Grades.keys()) // ['SILVER', 'Gold', 'pt', 'keys']
console.log(Grades.values()) // [2, 'Gold', 'platinum', 'keys']
console.log(Grades.map()) // { SILVER: 2, Gold: 'Gold', pt: 'platinum', keys: 'keys', '2': 'SILVER', platinum: 'pt' } Thank you for all you do. |
Hey folks. 🤚 Recently I have spend about 3 mins on this again. Currently:
Anyway. I hope we could improve the experience on this one. Thanks! |
As others have pointed out, this isn't just sugar—it has fundamental type safety, usability, and behavioral implications. I've renamed the issue to reflect this. Thanks to everyone (maintainers and commenters) for your support and patience; modifying languages is a lengthy process! |
It's really helpful when you write an big enum contains tons of value such as compiler TokenType |
This would be a super feature when StringEnumConverter is used on the web API side, for example, for API error codes enum. |
@RyanCavanaugh Is it still your opinion that this issue does not merit attention? |
Is there any progress? It is strongly recommended to add this function. You can also define a new enumeration keyword.
|
String Enum Initializer
A more typesafe and succinct way of defining enum types that compile to strings
Search Terms
enum, string, string enum
default value
initializer
infer
Proposal
It seems like you should be able to specify that you are using a string enum, and then you'd only have to write out the 'value' once, and it would be automatically made into a string matching the enum code.
or
instead of
Thanks for all the great work!
EDIT
Recently updated to reflect variations proposed by @imcotton here and @lostpebble here; as well as search terms proposed by @KennethKo (#36319) and @garrettmaring (#33015)
The text was updated successfully, but these errors were encountered: