9

I have a piece of TypeScript code like this:

enum EventType {
  EVENT_A = 'eventA',
  EVENT_B = 'eventB',
  ... // more event types
}

interface Event {
  type: EventType;
}

interface EventA extends Event {
  type: EventType.EVENT_A;
  data: PayloadForEventA;
}

interface EventB extends Event {
  type: EventType.EVENT_B;
  data: PayloadForEventB;
  id: number;
}

... // More Event interfaces

Is it possible to somehow map the values of EventType to corresponding interfaces? If it could not be done automatically, is it possible to specify the types mapped by the enum values manually?

I do know that it is possible to map values to types as shown in this question. And using the method shown below, it could create the lookup table I needed:

type EventTypeLut = {
  'eventA': EventA,
  'eventB': EventB,
  // ...
};

But this method hardcodes the value of enum into the LUT. The enum value might change in the future (which I don't have much control) and hardcoding the enum value makes it harder to maintain.

When I try to use EventType.EVENT_A as key name, TypeScript complains with "property or signature expected". Using template string seems also no avail. (It seems that the key name cannot be computed, even if it's a constant expression like 1+2.)

The reason I am trying to do this is I would like to create a typed EventEmitter with the enum value of EventType as name and respective typed object for callback function. If there is a better way to achieve this, please also give a hint. Thanks in advance.

2 Answers 2

6

In addition to @chharvey 's answer, you could also ensure all of the EventType keys are included in the EventTypeLut by doing something like:

type EventTypeLut = {
  [T in EventType]: {
    [EventType.EVENT_A]: EventA,
    [EventType.EVENT_B]: EventB,
  }[T]
};

The [T in Event] will cause TypeScript to complain if not all of the enum members are provided.

Sign up to request clarification or add additional context in comments.

1 Comment

I asked a follow-up question about how to enforce that the values corresponding to the enum keys match a certain other type, maybe you know the answer and/or this link will be helpful for other people who found this question: stackoverflow.com/q/74021822/5602521
3

Object literals (and thus interfaces and object types) can have computed keys. For example:

const obj = {
  [2 + 2]: 'four'
};
obj[2 + 2] === 'four'; // true
obj[1 + 3] === 'four'; // true
obj[4]     === 'four'; // true
obj['4']   === 'four'; // true

Computed keys are expressions wrapped in brackets that can be used as keys of an object literal, interface, or object type. Try using computed keys for your EventTypeLut object type:

type EventTypeLut = {
  [EventType.EVENT_A]: EventA,
  [EventType.EVENT_B]: EventB,
  // ...
};

1 Comment

Is there a way of "typing the type", or making sure that all of the EventType keys are included in EventTypeLut?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.