Repository navigation
Allow enums of types other than number #1206
Description
Activity
- addedSuggestionAn idea for TypeScriptAn idea for TypeScriptNeeds ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.This issue needs a plan that clarifies the finer details of how it could be implemented.
on Nov 19, 2014 From the original proposal
As in the title, and as discussed extensively here, it would be very helpful to allow enums of types other than number. At the very least, if allowing arbitrary types is too much work, string enums should be allowed. The current codegen for enums actually works with strings as-is, the compiler just flags errors.
Consider:
enum Dog{
Rover = 'My Dog',
Lassie = 'Your Dog'
}alert(Dog.Rover);
As of 0.9, this gets to compiled to:
var Dog;
(function (Dog) {
Dog[Dog["Rover"] = 'My Dog'] = "Rover";Dog[Dog["Lassie"] = 'Your Dog'] = "Lassie";
})(Dog || (Dog = {}));alert(Dog.Rover);
which is 100% functioning JavaScript that works as you expect it to.
In addition, the whole concept of "overloads on constants" would be a lot cleaner with a string-based enum:
interface Document {
createElement(tagName: TagName): HTMLCanvasElement;
}enum TagName{
Canvas = "canvas",
Div = "div",
Span = "span"
}var a = createElement(TagName.Canvas); //a is of type HTMLCanvasElement
Closed Jul 28 at 5:18 PM by jonturner
As part of our move to GitHub, we're closing our CodePlex suggestions and asking that people >move them to the GitHub issue tracker for further discussion. Some feature requests may already >be active on GitHub, so please make sure to look for an existing issue before filing a new one.
You can find our GitHub issue tracker here:
https://github.com/microsoft/typeScript/issuesChanged the one example from the original for the Document interface. It seems that you would only specify the name of the enum.-- Values passed in would become bounded to the use of the enum constants (and possibly to free-form string literals, where their values can be statically determined to be within the enum's domain values)
Joshua Lange (@jhlange) I think tagged unions would automatically cater for this use case nicely : #1003
Basarat Ali Syed (@basarat) That seems interesting from a theoretical standpoint, and I can definitely see uses for it.
It would solve my case.--At least giving some level of intellisense and compile-time validation.
I personally believe accessing enum constant fields makes for a much more natural experience for non-functional languages (and at least has parity with enums, which is what they they really are. I really don't think we should create a new concept for a construct that already exists. That will be confusing to too many people).
saschanaz commented
on Nov 19, 2014 ContributorMore actionsI would love this when I deal with C++ enums compiled by Emscripten.
// C++ enum Month { Jan, Feb, Mar };
// I can do this, but they really are not numbers! declare enum Month { Jan, Feb, Mar } interface EmscriptenEnum { value: number; /* some more properties ... */ } interface Month extends EmscritenEnum { } declare module Month { var Jan: Month; var Feb: Month; var Mar: Month; } // Month.Jan.value == 0, Month.Feb.value == 1, ...
C#/C++ lets you define base type of enum, although restricted to numeric type. I would like to be able to do the same but generalized to arbitrary type.
It should work with builtin types like string, so:
enum Foo extends string { BAR, BAZ = "surprise" }
compiles to:
var Foo; (function (Foo) { Foo["BAR"] = "BAR"; Foo[Foo["BAZ"] = "surprise"] = "BAZ"; })(Foo || (Foo = {}));
but also user types, to handle enum object pattern that is used by enums in Java and common in other languages (as requested above):
interface IFoo { id: string; code: number; } enum Foo extends IFoo { BAR = { id: "BAR", code: 123 }, BAZ = { id: "", code: 0 } }
compiles to:
var Foo; (function (Foo) { Foo["BAR"] = { id: "BAR", code: 123 }; Foo["BAZ"] = { id: "", code: 0 }; })(Foo || (Foo = {}));
Perhaps with a convention that if interface has fields
idand/orcode(orordinalas in Java) they can be omitted in initializer and filled by compiler.Reacted by Tushar Mathur, Josef Salyer, Naz, Anton Fedchenko and Alok SaldanhaHow would this work?
enum Test { Foo = "Bar", Bar = "Baz", Baz = "Foo" }
Either compilation error or omit generation of reverse mapping for Bar. I'm not sure which one I prefer.
In fact I'd prefer if TypeScript didn't generate reverse mapping in the same object. Perhaps all reverse mappings (for number based enums too) should go inside some property, say
Test.__reversed.In my mind these really need to compile down to plain strings. String enums
are already heavily used in json objects for Web services. In my opinion
this is one of the main use cases for string based enums.-- another example
is in the second post-- being able to define the domain values for
predefined Javascript apis.If it isn't possible to define strongly typed interfaces for these cases,
because typescript uses a different methodology in its implementation, the
implementation would be purely academic.
On Dec 30, 2014 3:16 PM, "Marcin Wisnicki" notifications@github.com wrote:In fact I'd prefer if TypeScript didn't generate reverse mapping in the
same object. Perhaps all reverse mappings (for number based enums too)
should go inside some property, say Test.__reversed.—
Reply to this email directly or view it on GitHub
#1206 (comment)
.I think the first thing should be strings const enum.
This is definitely the most useful feature.
Many APIs has JSON with small amount of possible string values and currently you must use 'string' type rather then a correct subset.
In that case I even think the names are not needed since you can pass only the correct string.const enum A { "x", "y", "z" } var a : A; a = // Intellisense suggest "x", "y" or "z" a = "x"; // OK a = "b"l // Error
My concern with the const enum approach is that it will lead to cases where the value can not be determined to be conforming when being passed into an API. (would this be a warning?, what happens if you get that warning? do you have to add casts all over the place to mitigate the warning?).
If you treat them as something that can never be converted to or from a string, they will do exactly what they need to do.-- It should work exactly like the integer enums, with the exception that the values are strings. I think it would be fine if the keys and values are locked together, meaning that
const enum A { "x", "y", "z" }Could be fine, but any string assignments without casts should fail.
public myfunc(someRandomInput: string) { var a : A; a = // Intellisense suggest A.x A.y A.z a = "x"; // Error, it is overkill to support this special case. Just use A.x like a regular enum a = A.x; // OK a = "b"; // Error a = someRandomInput; // Error, can not always be determined to be conforming. }In cases where they are converted from a string, a cast should be used.-- But even then, behavior like that can indicate that an input did not come from a proper source.
Additionally, this will help tooling like the the schema validation/generators to appropriately generate the appropriate validation code.-- Schema validation is going to become even more important in times to come.--One of my big concerns with javascript is general is the lack of validation.-- Now that people are running servers on this stuff.
As far as I can tell, the bulk of the work needed to get this done is removing one validation/compiler error against enum definitions (assigning types other than number).-- There might be some smarts to make sure people don't directly assign numbers to enum, but they shouldn't be doing that without a cast anyway either...
How about using generics for enum?
Current existingenummeansenum<number>. So we can extend it toenum<string>or other types:enum<string> Foo1 { BAR, // default value is "BAR". BAZ = "x" // also you can specify the vaule. } var e: Foo1 = Foo1.BAR; // ok var s: string = Foo1.BAR; // ok var n: number = Foo1.BAR; // error enum<boolean> Foo2 { BAR = true, // assigning is required. only number and string enum have default value. BAZ = false }
You can use every type for enum like
enum<YourFavoriteType>and there is no breaking change.Reacted by Sean Vieira, Rasmus Schultz, Ian MacLeod, Myrddin Emrys, Eward, Michał Lytek, Misha Vyrtsev, Phuoc Nguyen, David Guthrie, Alex and 11 more106 remaining items
In my scenario I needed sort of custom object enum, since my class does not have any method that would make the inheritance necessary, I just used this class with static props:
export class ViewerItemCardType { public static Big: ViewerItemCardType = new ViewerItemCardType(1, "FeaturedBig", 330, 660); public static Medium: ViewerItemCardType = new ViewerItemCardType(2, "FeaturedSmall", 155, 310); public static Small: ViewerItemCardType = new ViewerItemCardType(3, "NormalArticle", 100, 200); private constructor( public id: number, public name: string, public imageHeight: number, public imageWidth: number ) { }; }
I can access to these "complex" enums like:
ViewerItemCardType.Big.imageHeight ViewerItemCardType.Big ViewerItemCardType.Small@isiahmeadows , Does that particular scenario match with your definition at some point ?
Reacted by KleyguerthReacted by Rasmus Schultz and Patrick LienauJosé Quinto (@jquintozamora) that's awesome!
I think you can infer the extra type-hints though, and you'd likely want to define a means of enumerating the options as well, depending on your use-case - so like:
export class ViewerItemCardType { public static Big = new ViewerItemCardType(1, "FeaturedBig", 330, 660); public static Medium = new ViewerItemCardType(2, "FeaturedSmall", 155, 310); public static Small = new ViewerItemCardType(3, "NormalArticle", 100, 200); public static All: ViewerItemCardType[] = [ ViewerItemCardType.Big, ViewerItemCardType.Medium, ViewerItemCardType.Small ] private constructor( public id: number, public name: string, public imageHeight: number, public imageWidth: number ) { }; }Reacted by José Quinto and Aluan HaddadJosé Quinto (@jquintozamora) also note that it's a closed set though - you can't use declaration merging to add new values, so that's another thing we'd (hopefully) get from real typed enums.
Hi Rasmus Schultz (@mindplay-dk) ,
In my current scenario is really helpful when used in combitation with react - style attribute.
Indeed, it would be good to have a official solution for that like real typed complex enums. :)Implementation now available in #15486.
Reacted by normalser, Jan Žák, SlurpTheo, Jeremy Attali, Anatoly Ressin, Lucas Basquerotto, Gulshan, Daniel Busłowicz, Jay Phelps, Pablo Maurer and 1 moreReacted by Zev Spitz, normalser, José Quinto, Robert R., Pablo Moleri, Kelly Thomas Kline, Daniel Busłowicz, Teppei Sato, Clayton Watts, Pablo Maurer and 1 moreReacted by normalser, Daniel Busłowicz, José Quinto and Pablo Maurer- addedCommittedThe team has roadmapped this issueThe team has roadmapped this issueand removedIn DiscussionNot yet reached consensusNot yet reached consensus
on May 17, 2017 - addedFixedA PR has been merged for this issueA PR has been merged for this issue
on May 17, 2017 I released ts-enums as a library that enables creating full-class, Java-style enums. Maybe it can be useful for some people on this thread.
Suggestions for improvements are welcome :)
Reacted by Kagami Sascha Rosylight and normalserReacted by Sebastien DuboisWith Angular 2
//enumexport enum IType { Vegitable=0, Fruits=1, Fish=2 }// angular 2 Component in type script
import {IType} from '/itype'; export class DataComponent { getType(id:number):any { return IType[id]; } }// in your html file
<div> {{getType(1)}} </div>- locked and limited conversation to collaborators
on Jun 18, 2018
I'm reopening this issue, because it was closed with the move from codeplex, and doesn't seem to have been re-opened. https://typescript.codeplex.com/workitem/1217
I feel like this is very important for a scripting language.-- Especially for objects that are passed back and forth over web service calls.-- People generally don't use integer based enums in json objects that are sent over the wire, which limits the usefulness of the current enum implementation quite a bit.
I would like to re-propose the original contributor's suggestions verbatim.