为什么这个带有联合的可变元组类型似乎不允许匹配类型?

Why does this variadic tuple type with a union not appear to allow a matching type?

此代码似乎可以在 TS 4.3 中编译,但不能在 TS 4.3 之前(即 4.0.5 等)编译。我很困惑为什么向 undefined 添加联合会导致第二个赋值无法编译。我试图了解是什么改变使它可以在 4.3 中工作,但我不确定要搜索什么(如错误修复等)。此外,我正在寻找在版本可以升级之前使用 TS 4.3 之前的适当解决方法。例如,我应该只在 y 的类型定义上添加 | undefined,还是有其他方法让类型适合第二次赋值?

export type StringKeyOf<T> = Extract<keyof T, string>;

export interface GenericEvent<TEventName, TData> {
  eventName: TEventName;
  data: TData;
}

export type EventTypeByEventName = {
  [eventName: string]: any;
};

export type GenericEventsFromMap<TEventMap extends EventTypeByEventName, K2 extends keyof TEventMap> = {
  [K in K2]: GenericEvent<K, TEventMap[K]>;
}[K2];

export class EventService<TEventMap extends EventTypeByEventName> {
  public setup<T extends Array<StringKeyOf<TEventMap>>>(managerId: string, eventNames: [...T]) {
    const y: GenericEvent<T[number], TEventMap[T[number]]> = null as any;

    // this assignment works
    const z: GenericEventsFromMap<TEventMap, T[number]> = y;

    // this assignment gives:
    // Type 'GenericEvent<T[number], TEventMap[T[number]]>' is not assignable to type 'GenericEventsFromMap<TEventMap, T[number]>'.
    const z2: GenericEventsFromMap<TEventMap, T[number]> | undefined = y;
  }
}

playground link

有问题的错误是 microsoft/TypeScript#43152, and was fixed in microsoft/TypeScript#43202,它已于 2021-03-19 合并到主分支中,并最终与 TypeScript 4.3 一起发布。

我是怎么找到这个的?如果你去 https://typescript.azureedge.net/indexes/pre-releases.json you will see a list of TypeScript pre-release versions that you can use in The TypeScript Playground with the ts= query parameter. Via binary search,你可以相当快地找到存在错误的最后一个版本和没有错误的第一个版本。

在你的例子中,错误是 present in 4.3.0-dev.20210316 but absent in 4.3.0-dev.20210323. That means we'd need to search for pull requests merged between 2021-03-16 and 2021-03-23 and find which one is appropriate. If we add the "union" and "undefined" terms to our search 它进一步缩小了范围。


至于那些不幸被困在有这个错误的版本上的人的解决方法,目前还不清楚什么是好的。许多明显的修复都未能 运行 进入同一个错误,因为没有充分的理由为什么 X 不应该分配给 X | undefined。以下类型断言似乎有效:

const z: GenericEventsFromMap<TEventMap, T[number]> | undefined = 
  y as typeof y | undefined; // okay

但是否可取就很难说了。

Playground link