5

I would like to programmatically get the name of a TypeScript enum.

Say I have an enum like this:

enum MyEnum {
  v1 = 'v1',
  v2 = 'v2',
}

I would like to get the name of this enum programmatically. I tried the following:

const enumType = MyEnum
console.log(enumType.constructor.name) // I expect this to return "MyEnum"

But it displays "Object" instead.

Is there a way to get name of a TypeScript enum programmatically?

Ivan Mushketyk
  • 8,107
  • 7
  • 50
  • 67
  • 2
    You're essentially asking "how to get the name of a variable" and there is no way to do it. – VLAZ Jan 20 '20 at 11:54
  • 2
    Does this answer your question? [Variable name as a string in Javascript](https://stackoverflow.com/questions/4602141/variable-name-as-a-string-in-javascript) – VLAZ Jan 20 '20 at 11:58
  • @VLAZ I think you've misunderstood my question. I want to get the name of the Enum type (MyEnum in this case), not the name of a variable (enumType in this example). I don't see how these are equivalent. – Ivan Mushketyk Jan 20 '20 at 11:59
  • `enum` transpired to an object (variable). Have a [look](https://www.typescriptlang.org/play/index.html#code/KYOwrgtgBAsgngUXNA3gWAFBSgNwIxQC8UA5PiQDSbY4BMRpdlmAvkA) – Aleksey L. Jan 20 '20 at 12:00
  • 1
    Please go through this link might solve your problem https://stackblitz.com/edit/typescript-enum-sample?file=index.ts – Dinshaw Raje Jan 20 '20 at 12:01
  • @IvanMushketyk no, I've not misunderstood it. Enums are compiled into objects that have two-way bound variables and keys to ensure uniqueness. At *compile time*, TS will try to ensure you don't use the wrong key/value. At *runtime* you lose the type system but are left with a plain JS object that carries the same semantics. So, when you do `const enumType = MyEnum` you're assigning *a JavaScript variable* to `enumType`. You now want to lookup the name of the *original* variable you've created a second binding for. That's not possible. – VLAZ Jan 20 '20 at 12:06
  • `console.log(((o: {}) => Object.keys(o)[0])({ MyEnum })) // "MyEnum"` – ford04 Jan 20 '20 at 12:22
  • @IvanMushketyk you can see the [runtime content of an enum here](http://www.typescriptlang.org/play/#code/KYOwrgtgBAsgngUXNA3gKClAbgRigXigHJciAaDbAJgOKyvLQF800BjAexAGcOAbYADo+HAOYAKeEkgBKANxogA) as well as the actual JS equivalent you get for a TS enum. Since TS does not in any way hold the name of an enum, what you get is simply a variable called `MyEnum` that holds an object. Whether or not you create a second variable to it, you still want to see the name a variable has. – VLAZ Jan 20 '20 at 12:24
  • @VLAZ Thank you! Could you write this up as an answer? I would approve it. – Ivan Mushketyk Jan 20 '20 at 13:33

1 Answers1

9

First, off the type system exists only at compile time. When you have

enum MyEnum {
  v1 = 'v1',
  v2 = 'v2',
}

Then TypeScript knows about the enums and ensures that doing MyEnum['v1'] is correct but raising a compile time problem for MyEnum['banana'].

Once the code is compiled, however, you have pure JavaScript. This is what gets executed at runtime.

Enums get compiled to plain JavaScript objects double binding the keys and values. That way TS ensures the uniqueness of the enum values at runtime. The example enum given gets turned into:

var MyEnum;
(function (MyEnum) {
    MyEnum["v1"] = "v1";
    MyEnum["v2"] = "v2";
})(MyEnum || (MyEnum = {}));

See on TypeScript Playground

Once executed you get a MyEnum variable that holds the plain object { v1: "v1", v2: "v2" }

I did say that TS will double-bind the keys and values. The example above doesn't demonstrate it well, so here is another one:

enum ExampleEnum {
  Apple = 1,
  Banana = 2,
}

will be turned into the plain object:

{ 
  1: "Apple", 
  2: "Banana", 
  Apple: 1, 
  Banana: 2 
}

See on TypeScript Playground

Thus both the keys (Apple and Banana) are unique, as would be the values (1 and 2), since they are all turned into keys of an object and you cannot have duplicate keys. It also allows you do do MyEnum[MyEnum[key]] to fetch what key is.

I don't suggest having duplicate values in your enum. Technically possible but you likely shouldn't. you'd have problems if you do MyEnum[MyEnum[key]]

At any rate, TypeScript does not encode the enum name as part of the enum, so once you're at runtime, you just have a plain JavaScript variable to work with. And you cannot get the name of a variable in JavaScript. At best, you can do something like:

function printVariableName(input) {
  console.log("Name:", Object.keys(input)[0]);
  console.log("Value:", Object.values(input)[0]);
}

var myVariable = 42;

printVariableName({myVariable});

However, this is just cheating a bit - you're passing an object which contains { myVariable: 42 }. This only works if you already know what the variable is, so it's of little use if you want to get the name indirectly though a different variable:

function printVariableName(input) {
  console.log("Name:", Object.keys(input)[0]);
  console.log("Value:", Object.values(input)[0]);
}

var myVariable = 42;
var myOtherVariable = myVariable;

printVariableName({myOtherVariable});

So, you you're passing around enums, e.g. you have a function like:

function doSomethingWithEnum(someEnum: MyEnum | MyOtherEnum): void {
  //do something with the passed in `someEnum`
}

Then if you call doSomethingWithEnum(MyEnum) then inside the body of the function you cannot de-reference what the passed in variable was.

VLAZ
  • 26,331
  • 9
  • 49
  • 67