问题描述
我有一个可区分联合的映射,从联合类型到使用联合成员作为参数的函数:
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)
}
但是,由于以下原因无法编译:
“Applicable”类型的参数不能分配给“never”类型的参数。
交集“添加和附加”被减少为“从不”,因为属性“类型”在某些成分中具有冲突类型。
“添加”类型不可分配给“从不”类型。ts(2345)
这让我感到非常惊讶,因为我希望 TypeScript 能够正确推断这将始终是一个有效的调用。
到目前为止我发现的唯一解决方法是将其称为 applicableMap[applicable.type](s,applicable as any)
,但是我发现使用 any
总是一种黑客行为。
现在的问题是:
这只是当前的 TypeScript 限制,还是有一种方法可以在保留类型推断和详尽检查的同时调整此处的类型?
解决方法
检查 https://github.com/microsoft/TypeScript/issues/30581 这似乎是 Typescript 编译器中公认的限制,并且与我认为的问题大致相同。