Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you type an enum variable in typescript?

I saw that in various stackoverflow answers on how to access an enum in html says to define a variable on the component and set it equal to the enum, like in this question. But, what would be the type?

To use their example:

enum MyEnum{
  First,
  Second
}

export class MyComponent{
  MyEnum = MyEnum;
  myEnumVar:MyEnum = MyEnum.Second
  ...
}

<div [ngSwitch]="myEnumVar">
  <div *ngSwitchCase="MyEnum.First"><app-first-component></app-first-component></div>
  <div *ngSwitchCase="MyEnum.Second"><app-second-component></app-second-component></div>
  <div *ngSwitchDefault>MyEnumVar {{myEnumVar}} is not handled.</div>
</div>

myEnumVar was typed, but MyEnum was not. What am I supposed to type it as?

like image 432
evereveron Avatar asked Apr 09 '18 00:04

evereveron


2 Answers

Because enums are created as plain {}, their type is actually object.

For instance, the enum:

enum MyEnum{
  First,
  Second
}

is transpiled to:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["First"] = 0] = "First";
    MyEnum[MyEnum["Second"] = 1] = "Second";
})(MyEnum || (MyEnum = {}));
           // ^^^^^^^^^^^ --- important part

Notice MyEnum is, in the end, an object ({}) with added properties later. More specifically, with number keys and string values (see more below).


So, if you wish to declare a type, you have some alternatives.

For starters, you can use object or any, like below (but check the other alternatives as well):

export class MyComponent{
  MyEnum:Object = MyEnum;
  myEnumVar:MyEnum = MyEnum.Second
  ...
}

Index signature type

Another option, for enums, you can also use the type {[s: number]: number | string}:

export class MyComponent{
  MyEnum:{[s: number]: number | string} = MyEnum;
  myEnumVar:MyEnum = MyEnum.Second
  ...
}

typeof

Or, as pointed by Gerrit0 (see their answer for the full info and due credits):

export class MyComponent{
  MyEnum:typeof MyEnum = MyEnum;
  myEnumVar:MyEnum = MyEnum.Second
  ...
}
like image 77
acdcjunior Avatar answered Nov 14 '22 09:11

acdcjunior


While acdcjunior's answer is technically correct - yes, an enum is an object, and yes it can be described with the {[s: number]: string} type, this is not how you should type the MyEnum property.

An enum contains both string and number values, so at the very least the index signature should be { [s: number]: string | number } - MyEnum[1] === "First" while MyEnum.First === 1.

However, TypeScript provides a better way of doing this, the typeof operator. This is different from JavaScript's typeof - when you use typeof in a type declaration, it gets the type of a value and is not constrained to primitives and object.

To highlight the difference, here's an example:

enum MyEnum {
  First,
  Second
}

class MyComponent {
  static MyEnum: typeof MyEnum = MyEnum
  static MyObjectEnum: { [s: number]: string | number } = MyEnum
}

// a is `any`
// can't use MyComponent.MyObjectEnum.First
let a = MyComponent.MyObjectEnum['First']
// b is `MyEnum`
let b = MyComponent.MyEnum['First'] // or MyComponent.MyEnum.First
// c is `any`
let c = MyComponent.MyObjectEnum['Third']
// d is `any`
// using MyComponent.MyEnum.Third catches this error
let d = MyComponent.MyEnum['Third']
// neither catch this error
// e is type `string`
// f is type `string | number`
let e = MyComponent.MyEnum[3]
let f = MyComponent.MyObjectEnum[3]

If you look at the type inferred by your IDE when trying to type something, you can learn a lot about what types should be used.

intellisense

like image 25
Gerrit0 Avatar answered Nov 14 '22 09:11

Gerrit0