3

I can obtain a type representing the keys of an interface with:

interface I { a: string; b: string; }
const i: keyof I; // typeof i is "a" | "b"

Is there a way to similarly obtain a type representing the values of an enum?

enum E { A = "a", B = "b" }
const e: ?; // typeof e is "a" | "b"
rid
  • 61,078
  • 31
  • 152
  • 193

3 Answers3

2

The list of values of an enum can be infered as a type with some help of the template literal operator:

enum E { A = "a", B = "b" }

type EValue = `${E}`
// => type EValue = "a" | "b"

const value: EValue = "a" // => ✅ Valid
const valid: EValue = "b" // => ✅ Valid
const valid: EValue = "" // =>  Invalid

Reference article: Get the values of an enum dynamically (disclaimer: author here)

Arnaud Leymet
  • 5,995
  • 4
  • 35
  • 51
1
enum E { A = "a", B = "b" }
const e: keyof typeof E;

Playground example

Maarti
  • 3,600
  • 4
  • 17
  • 34
  • 1
    Unfortunately, the type of `e` is `"A" | "B"` (the enum cases), not `"a" | "b"` (the enum values). – rid Oct 26 '18 at 21:24
  • Oh, so just do `const e: E` no ? Edit: I see in this [playground](http://www.typescriptlang.org/play/index.html#src=enum%20Name%20%7B%0D%0A%20%20%20%20Fred%20%3D%20%22F%22%2C%20Vilma%20%3D%20%22V%22%0D%0A%7D%0D%0A%0D%0Alet%20a%3A%20Name%20%3D%20%22F%22%3B) that the autocompletion works but there is the "is not assignable" warning. – Maarti Oct 26 '18 at 21:30
  • `E` is the enum type. I'm looking for the type of its values, which is a union of the string types `"a"` and `"b"` (`"a" | "b"`). – rid Oct 26 '18 at 21:59
0

In fact, the name of the enum is, itself, an alias for the union of its values' types. The following code demonstrates:

enum WaterType {
    Lake  = 0,
    Ocean = 1,
    River = 2,
    Creek = 3,
};

let xxx: 0|1|2|3 = 2;
let yyy: WaterType = xxx; // OK
let zzz: 0|1|2|3 = yyy;   // OK

Enums are just a little confusing because the enum's name refers to the type (like 0|1|2|3) in some contexts, but in other contexts it refers to an object by the same name. The WaterType object is similar to this object:

const WaterTypeObject = {
    Lake  : 0 as 0,
    Ocean : 1 as 1,
    River : 2 as 2,
    Creek : 3 as 3,
};

And typeof WaterType is virtually the same as typeof WaterTypeObject:

let aaa: typeof WaterType       = WaterType;
let bbb: typeof WaterTypeObject = aaa; // OK
let ccc: typeof WaterType       = bbb; // OK

In contexts where a type is expected, WaterType means 0|1|2|3, but you can write typeof WaterType instead to get the type of the enum object:

// VS code reports: type WaterTypeString = "Lake" | "River" | "Ocean" | "Creek"
type WaterTypeString = keyof typeof WaterType;
// VS code reports:   type WaterTypeNumbers = WaterType
// which really means type WaterTypeNumbers = 0|1|2|3
type WaterTypeNumbers = (typeof WaterType)[WaterTypeString];

Just be sure not to write "keyof Enum", e.g. keyof WaterType is the same as keyof number, which is definitely not what you want.

Fun fact: keyof typeof WaterType is a lie. the keys of WaterType are actually "Lake"|"River"|"Ocean"|"Creek"|0|1|2|3 (e.g. WaterType["Creek"]==3 and WaterType[3]=="Creek".)

Qwertie
  • 16,354
  • 20
  • 105
  • 148