0

For example I have a type EventMapping which is a map "eventName -> eventData". I need to store emitted events in a list. Thus I want to transform this map to type Event, so I can't push data of incorrect type into the events list.

// type which i have
type EventMapping = {
  click: {
    position: Point;
  };
  scroll: {
    top: number;
    bottom: number;
  };
}

// type which i want to get
type Event = {
  type: 'click';
  data: {
    position: Point;
  };
} | {
  type: 'scroll';
  data: {
    top: number;
    bottom: number;
  };
}

// usage example
const events: Event[] = [];

// ok
events.push({
  type: 'scroll',
  data: {
    top: 0,
    bottom: 0,
  }
});

// error
events.push({
  type: 'click',
  data: {
    top: 0,
    bottom: 0,
  }
});
Gnut
  • 541
  • 1
  • 5
  • 19
keshaLt
  • 3
  • 1

2 Answers2

0

My strategy is 2 steps:

  1. Convert the type EventMapping to an union of keys: so the goal is to get

    "scroll" | "click"

    This can be accomplished with the keyof operator

  2. From this union I map it your event type. Using the trick mentioned here: Map union to another union type

The result is:

type Distribute<U> = U extends keyof EventMapping? {type: U, data: EventMapping[U]} : never;

type Event = Distribute<keyof EventMapping>
Gnut
  • 541
  • 1
  • 5
  • 19
0

Solution using a mapped type:

type ObjectToUnion<T> = {[K in keyof T]: {type: K, data: T[K]}}[keyof T]

type EventUnion = ObjectToUnion<EventMapping>

Playground Link

kaya3
  • 47,440
  • 4
  • 68
  • 97