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 = {
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[]]> };