如何在打字稿中将对象类型转换为联合?

How to transform object type to union in typescript?

例如,我有一个 EventMapping 类型,它是一个映射“eventName -> eventData”。我需要将发出的事件存储在列表中。因此,我想将此映射转换为事件类型,因此我无法将不正确类型的数据推送到事件列表中。

// 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,
  }
});

我的策略是 2 个步骤:

  1. 将类型 EventMapping 转换为键的联合:所以目标是得到

    “滚动” | “点击”

    这可以通过 keyof 运算符

    来完成
  2. 从这个联合中,我将其映射到您的事件类型。使用此处提到的技巧:

结果是:

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

type Event = Distribute<keyof EventMapping>

使用 mapped type 的解决方案:

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

type EventUnion = ObjectToUnion<EventMapping>

Playground Link