3

So I've read all the posts on String Based Enums in Typescript, but I couldn't find a solution that meets my requirements. Those would be:

  • Enums that provide code completion
  • Enums that can be iterated over
  • Not having to specify an element twice
  • String based

The possibilities I've seen so far for enums in typescript are:

  1. enum MyEnum {bla, blub}: This fails at being string based, so I can't simply read from JSONs which are string based...
  2. type MyEnum = 'bla' | 'blub': Not iterable and no code completion
  3. Do it yourself class MyEnum { static get bla():string{return "bla"} ; static get blub():string{return "blub"}}: Specifies elements twice

So here come the questions:

  1. There's no way to satisfy those requirements simultaneously? If no, will it be possible in the future?
  2. Why didn't they make enums string based?
  3. Did someone experience similar problems and how did you solve them?
bersling
  • 17,851
  • 9
  • 60
  • 74
  • Please see [TypeScript docs for String Based Enums](https://basarat.gitbooks.io/typescript/content/docs/tips/stringEnums.html). Also [this](http://stackoverflow.com/questions/15490560/create-an-enum-with-string-values-in-typescript) post might help you out. – Nicky Sep 02 '16 at 08:50
  • 1
    Can you give an example of code which couldn't "simply read from JSONs which are string based"? – Paleo Sep 02 '16 at 08:51
  • **See Also**: [Create an enum with string values](https://stackoverflow.com/q/15490560/1366033) – KyleMit Jan 02 '22 at 01:34

2 Answers2

3

I think that implementing Enum in a C-like style with numbers is fine, because an Enum (similar to a Symbol) is usually used to declare a value that is uniquely identifiable on development time. How the machine represents that value on run time doesn't really concern the developer.

But what we developer sometimes want (because we're all lazy and still want to have all the benefits!), is to use the Enum as an API or with an API that does not share that Enum with us, even though the API is essentially an Enum because the valid value of a property only is foo and bar.

I guess this is the reason why some languages have string based Enums :)

How TypeScript handles Enums

If you look at the transpiled JavaScript you can see that TypeScript just uses a plain JavaScript Object to implement an Enum. For example:

enum Color {
    Red,
    Green,
    Blue
}

will be transpiled to:

{
  0: "Red",
  1: "Green",
  2: "Blue",
  Blue: 2,
  Green: 1,
  Red: 0
}

This means you can access the string value like Color[Color.Red]. You will still have code completion and you do not have to specify the values twice. But you can not just do Object.keys(Color) to iterate over the Enum, because the values exist "twice" on the object.

Sebastian Sebald
  • 16,130
  • 5
  • 62
  • 66
2

Why didn't they make enums string based

To be clear Enums are both number and string based in that direct access is number and reverse map is string (more on this).

Meeting your requirement

You key reason for ruling out raw enums is

so I can't simply read from JSONs which are string based...

You will experience the same thing e.g. when reading Dates cause JSON has no date data type. You would new Date("someServerDateTime") to convert these.

You would use the same strategy to go from server side enum (string) to TS enum (number). Easy done thanks to the reverse lookup MyEnum["someServerString"]

Hydration

This process of converting server side data to client side active data is sometimes called Hydration. My favorite lib for this at the moment is https://github.com/pleerock/class-transformer

I personally handle this stuff myself at the server access level i.e. hand write an API that makes the XHR + does the serialization.

At my last job we automated this with code generation that did even more than that (supported common validation patterns between server and client code).

basarat
  • 261,912
  • 58
  • 460
  • 511
  • "Enums are both number and string" -> okay, but I'd like to do something like e.g. in angular `ng-if="myObject.type === 'bla'"`, which won't work, unless I do the hydration you mentioned. What I would prefer would be a purely string based enumeration of the enum, somewhat like the DIY class in the question. Are there advantages of having a mixed numer / string map for enums like in typescript? – bersling Sep 02 '16 at 13:17
  • I think you're trying to use language feature that doesn't solve your problem. But you can always implement a simple method to "implement" your string-based enums. Also, you could use TypeScript's Enum to use with `ng-if`. You just have to do `ng-if="myObject.type === TypeEnum.Bla"` – Sebastian Sebald Sep 04 '16 at 14:39
  • Sorry... Typo: `ng-if="myObject.type === TypeEnum[TypeEnum.Bla]"` – Sebastian Sebald Sep 04 '16 at 14:47