Home > front end >  Declaring a type for an object where its keys discriminate value types from array union
Declaring a type for an object where its keys discriminate value types from array union

Time:01-18

I believe it is the best to illustrate that in a clear example:

enum EventType { A, B, C };

type MyEvent =
  [EventType.A, number] |
  [EventType.B, string] |
  [EventType.C, number, string];

const eventsGrouped: Record<EventType, MyEvent[]> = {
  [EventType.A]: [],
  [EventType.B]: [],
  [EventType.C]: [],
};

The goal is to create a type for eventsGrouped object that discriminates value type based on the key

In pseudocode:

Record<EventType, MyEvent where MyEvent[0] === object entry key>

So that:

  • eventsGrouped[EventType.A] is of type [EventType.A, number]
  • eventsGrouped[EventType.B] is of type [EventType.B, string]
  • eventsGrouped[EventType.C] is of type [EventType.C, number, string]

CodePudding user response:

Very simple with key remapping introduced in version 4.1:

type EventsGrouped = { [T in MyEvent as T[0]]: T };

It's a little hard to digest at first, but we are "looping" over the union, and for each member of the union, we use T[0] as the key, and T as the value.

Then you can use this as the type for eventsGrouped:

const eventsGrouped: EventsGrouped = {

Playground


Pre 4.1, still possible with mapped types! It needs extra work because you need to manually extract the corresponding member back out:

type EventsGrouped = { [K in MyEvent[0]]: Extract<MyEvent, [K, ...any[]]> };

Playground

  • Related