microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.95k stars 12.47k forks source link

Feature request: Decorators on enum members #3279

Open qc00 opened 9 years ago

qc00 commented 9 years ago

It would be nice to be able to decorate enum members (in the same way as properties?).

igabesz commented 9 years ago

Indeed, it could save lots of copy-paste code, e.g. when making string <--> enum conversions which is a strong industrial case.

Now I do this a lot:

enum AnimalType { 
  Cat, 
  Dog,
  Invalid
}
module AnimalType {
  export function parse(str:string):AnimalType {
    switch(type) {
      case 'cat': return AnimalType.Cat;
      case 'dog': return AnimalType.Dog;
      default: return AnimalType.Invalid;
    }
  }
  export function toString(type: AnimalType): string { /* ... */ }
}

How nice would this be:

enum AnimalType {
  @parse('cat')
  Cat, 
  @parse('dog')
  Dog,
  @parseDefault('invalid') /* parses everything, toString returns 'invalid' */
  Invalid
}
mhegazy commented 9 years ago

@igabesz can you explain how parse would be implemented? what does it return?

igabesz commented 9 years ago

I'm thinking of something like the C# DisplayName annotation. The main point is that @parse stores the string given to it; this string can be retrieved somehow through some metadata. The rest of the string-to-enum mapping should be implemented in a given function, but only once, not once per enum type.

I'm not very familiar with the current annotation syntax (btw any good and deep tutorials?), but I imagine something like this.

var AnimalType = (function(AnimalType) {
  AnimalType = {
    Cat = 0,
    Dog = 1
  }
  // this is some annotation or decorator container
  Object.defineProperty(AnimalType, '__decorators', {
    enumerable: false,
    configurable: false,
    writable: true,
    value: {} // or maybe a Set?  
  });
  // Something like this should be auto-generated
  // Can be in a different format, e.g. AnimalType and value could be passed too
  AnimalType.__decorators[AnimalType.Dog] = [ new parse('dog') ];
  AnimalType.__decorators[AnimalType.Cat] = [ new parse('cat') ];
  return AnimalType; 
}) (AnimalType || {});

// Defining annotation (just the relevant part)
function parse(str) {
  this.__annotationName = 'parse';
  this.str = str;
}

// One must implement these two functions by hand
// But they are general so they can be used with any enums 
function printEnum(enumType, value) {
  var annotations = enumType.__decorators[value];
  var parseAnnotation = getParseFromList(annotations);
  return parseAnnotation.str; 
}
function readToEnum(enumType, str) {
  var decorators = enumType.__decorators; 
  var value = selectEnumValueWhereTheParseAnnotationMatches(str); 
  return value; 
}
mhegazy commented 9 years ago

This is significantly different behavior from what decorators mean for classes. this means that you can not take your knowledge of writing a class /ES7 decorator to enums.

ghost commented 8 years ago

+1

niemyjski commented 7 years ago

+1

danilobjr commented 7 years ago

+1

ss108 commented 7 years ago

+1 to being able to decorate enum properties just like the props of any other object

sevensc commented 7 years ago

+1

rk-7 commented 6 years ago

👍 We definitely need decorators for enum members.

b3ross commented 6 years ago

Any update on this?

kbalint commented 6 years ago

+1

mmeasor commented 6 years ago

+1

KrakerXyz commented 6 years ago

+1

admin-fsoft commented 6 years ago

+1

igabesz commented 6 years ago

Currently TypeScript implements an older and now obsolete version of the ES Decorator proposal. The TypeScript Roadmap mentions the implementation of the new syntax, however it is not scheduled yet. (Well, it seems to be a huge pain with lots of coordination and breaking changes.)

I guess if there is any progress then it should be according to the new decorator syntax for classes -- as much as it can be applied on enums. Any official word on this?

carsoni commented 6 years ago

Definitely required

winuxue commented 5 years ago

any update?

alannsiqueira commented 5 years ago

+1

activebiz commented 5 years ago

+1 Would be great feature.

spyter commented 5 years ago

+1

shellscape commented 4 years ago

Let's keep this one at the forefront.

orta commented 4 years ago

Until the JS standard body has made some concrete decisions on what decorators should look and act like, we're unlikely to be adding new decorator features to TypeScript. Please don't add +1 comments unless you have something new to add.

cztomsik commented 4 years ago

There's a new, simpler proposal (again at stage2) for decorators - since when will you consider adding new features like this one? It could save us some boilerplate with graphql enum registering (but we'd need to somehow get the enum name).

jodinathan commented 3 years ago

I have 3 forms of using the next enum:

enum Foo {
  bar,
  daz
}

class Some {
   foo: Foo = Foo.bar;
}
  1. As a value like the property in Some.foo. So devs can do some.foo == Foo.bar
  2. As a graphql result:
    query {
    foo
    }

    The above should result in 'bar'

  3. And as a value in the database and it is different from the enum label.

If I add a value to the enum, ie enum Foo { bar = 1 } then frontend devs that uses the result of a graphql fetch can't do some.foo == Foo.bar because some.foo, that comes from graphql, would be 'bar' and not 1.

So the best option to us would be:

enum Foo {
  @val(1)
  bar,
  @val(2)
  daz
}

so the values of the enums would only be used in the database.

poerlang commented 2 years ago

some one may need this code:

export class Enum extends Number {
    private static ___value_to_key___: any = {}
    private static ___value_to_info___: any = {}

    static valueToKey(value: any) {
        return this.___value_to_key___[value]
    }

    static valueToInfo(value: any) {
        return this.___value_to_info___[value]
    }
}

export function AddInfo(info: any) {
    return (a_enum_class: any | Enum, key: any) => {
        const value = a_enum_class[key];
        a_enum_class.___value_to_key___[value] = key;
        a_enum_class.___value_to_info___[value] = info;
    }
}

export class FooEnum extends Enum {
    @AddInfo('一') static one = 1;
    @AddInfo('二') static two = 2;
    @AddInfo('三') static three = 3;
}

https://github.com/poerlang/typescript-enum-class-decorators

poerlang commented 2 years ago

some other code ( how to use the FooEnum / Enum )

    let theType: FooEnum =  FooEnum.three; // set a enum
    if (theType === FooEnum.one)  console.log('yes') // use Enum in if 
    FooEnum.one // get value
    FooEnum.valueToKey(FooEnum.one) // get key
    FooEnum.valueToInfo(FooEnum.one) // get info

Note: It is necessary to add the setting in tsconfig.json:

{
  "compilerOptions": {
    "experimentalDecorators": true,

    ... // other setting
  }
}
Will-at-FreedomDev commented 1 year ago

Until the JS standard body has made some concrete decisions on what decorators should look and act like, we're unlikely to be adding new decorator features to TypeScript. Please don't add +1 comments unless you have something new to add.

How long would we wait until the JS standard body has made some concrete decisions before TypeScript implements this? It's been 8 years now, maybe at 10 years? :)

I'm also a little confused on why we are waiting on the JS standard body. Aren't enums a TypeScript concept anyway?

What if this came via an experimental version or something that lets people know that we can use it, but may break in the future?

+1

ctsstc commented 10 months ago

If folks just want this for parsing, why not ask for a parser, that seems to be such a standard use case, but such a headache to handle typing properly without casting something along the way.

jellodev commented 9 months ago

any update for this?