【问题标题】:Mapping union tuple types, preserving the distribution映射联合元组类型,保留分布
【发布时间】:2026-01-11 06:30:01
【问题描述】:

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

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 成语,正如这个答案所建议的那样:TypeScript: Map union type to another union type

但它没有成功。

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

有什么方法可以逐个映射联合,以便在访问元组的第一个和第二个元素时不会混淆它们?

类似于地图操作,但针对类型。

【问题讨论】:

    标签: typescript typescript2.0


    【解决方案1】:

    Distributive conditional type 将在这里完成工作:

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

    Playground

    【讨论】: