映射联合元组类型,保留分布

Mapping union tuple types, preserving the distribution

我正在尝试为事件发射设置两个不同的重载:一个映射到自定义事件,具有众所周知的侦听器参数(因此调度时间参数)

export type EngineEvents
  = ['window-exit', () => void]
  | ['test', (code: number) => void]
  | ['pre-init', () => void]
  | ['post-init', () => void]
  | ['tick-start', () => void]
  | ['draw-start', () => void]
  ;

这里的问题是将这些类型映射到调度类型,而不必从头再来,我尝试了以下方法:

export type EventArgs = [EngineEvents[0], ...Parameters<EngineEvents[1]>];

但这会扩展为在每个单元格中包含联合的元组,这不是我想要的。我想以相反的方式映射元组,例如:

// Instead of
type A = [ 'a' | 'b', 1 | 2 ];
// Have this:
type B = [ 'a', 1 ] | [ 'b', 2 ];

我试过使用这个答案建议的 T extends any? whatever : never 习语:

但是没有成功。

export type ArgumentExpand<U> = U extends any[]? [U[0], ...U[1]] : never;

是否有任何方法可以逐个映射并集,以便在访问元组的第一个和第二个元素时不会混淆它们?

类似于映射操作,但针对的是类型。

Distributive conditional type 将在此处完成工作:

type MapArgs<E> = E extends [string, (...args: any[]) => any]
    ? [E[0], ...Parameters<E[1]>] : never;

type EventArgs = MapArgs<EngineEvents>;

Playground