镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Allow enums of types other than number #1206

Description

@jhlange

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.

Activity

  1. added
    SuggestionAn idea for TypeScript
    Needs ProposalThis issue needs a plan that clarifies the finer details of how it could be implemented.
    on Nov 19, 2014
  2. jhlange commented on Nov 19, 2014

    @jhlange
    Author

    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/issues

  3. jhlange commented on Nov 19, 2014

    @jhlange
    Author

    Changed 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)

  4. basarat commented on Nov 19, 2014

    @basarat
    Contributor

    Joshua Lange (@jhlange) I think tagged unions would automatically cater for this use case nicely : #1003

  5. jhlange commented on Nov 19, 2014

    @jhlange
    Author

    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).

  6. saschanaz commented on Nov 19, 2014

    @saschanaz
    Contributor

    I 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, ...
  7. mwisnicki commented on Dec 30, 2014

    @mwisnicki

    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 id and/or code (or ordinal as in Java) they can be omitted in initializer and filled by compiler.

  8. enoshixi commented on Dec 30, 2014

    @enoshixi

    How would this work?

    enum Test {
        Foo = "Bar",
        Bar = "Baz",
        Baz = "Foo"
    }
  9. mwisnicki commented on Dec 30, 2014

    @mwisnicki

    Either compilation error or omit generation of reverse mapping for Bar. I'm not sure which one I prefer.

  10. mwisnicki commented on Dec 30, 2014

    @mwisnicki

    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.

  11. jhlange commented on Dec 30, 2014

    @jhlange
    Author

    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)
    .

  12. NN--- commented on Jan 28, 2015

    @NN---

    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
  13. jhlange commented on Feb 20, 2015

    @jhlange
    Author

    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...

  14. teppeis commented on Feb 25, 2015

    @teppeis

    How about using generics for enum?
    Current existing enum means enum<number>. So we can extend it to enum<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.

  15. 106 remaining items

  16. jquintozamora commented on Apr 23, 2017

    @jquintozamora

    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 ?

  17. mindplay-dk commented on Apr 23, 2017

    @mindplay-dk

    José 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
        ) { };
    }
    
  18. mindplay-dk commented on Apr 23, 2017

    @mindplay-dk

    José 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.

  19. jquintozamora commented on Apr 24, 2017

    @jquintozamora

    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. :)

  20. ahejlsberg commented on May 1, 2017

    @ahejlsberg
    Member

    Implementation now available in #15486.

  21. LMFinney commented on Jul 31, 2017

    @LMFinney

    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 :)

  22. shafeeqthayyil commented on Aug 22, 2017

    @shafeeqthayyil

    With Angular 2
    //enum

    export 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>
    
  23. locked and limited conversation to collaborators on Jun 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

CommittedThe team has roadmapped this issueFixedA PR has been merged for this issueSuggestionAn idea for TypeScript

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions