从联合类型映射调用函数

Calling a function from a map of union types

我有一个从联合类型到使用联合成员作为参数的函数的可区分联合映射:

export interface Truncate {
  type: 'truncate'
  maxLength: number
}

export interface Append {
  type: 'append'
  suffix: string
}

export type Applicable = Truncate | Append

const applicableMap: { [K in Applicable['type']]: (base: string, applicable: Extract<Applicable, { type: K }>) => string } = {
  'truncate': (s, applicable) => {
    return s.slice(0, applicable.maxLength)
  },
  'append': (s, applicable) => {
    return s + applicable.suffix
  }
}

到目前为止一切顺利; TypeScript 正确推断每个函数中 applicable 参数的类型并对键执行详尽检查,所以如果我添加新成员,我不会不小心忘记向映射添加条目。

现在,我有一个 apply 函数,它从映射中选择一个函数并尝试调用它:

function apply(s: string, applicable: Applicable): string {
  return applicableMap[applicable.type](s, applicable)
}

但是编译失败,原因如下:

Argument of type 'Applicable' is not assignable to parameter of type 'never'.
The intersection 'Add & Append' was reduced to 'never' because property 'type' has conflicting types in some constituents.
Type 'Add' is not assignable to type 'never'.ts(2345)

这让我感到非常惊讶,因为我希望 TypeScript 能够正确推断这将始终是一个有效调用。

到目前为止我发现的唯一修复方法是将其称为 applicableMap[applicable.type](s, applicable as any),但我发现使用 any 总是很麻烦。


现在的问题是:

这只是当前 TypeScript 的限制,还是有办法在保留类型推断和详尽检查的同时调整此处的类型?

检查 https://github.com/microsoft/TypeScript/issues/30581,这似乎是 Typescript 编译器中公认的限制,并且与我认为的问题大致相同。