为什么TypeScript无法收窄可辨识联合类型导致函数调用报错
报错原因
TypeScript 不会跟踪不同变量之间的类型关联关系,你把fn和arg从联合类型对象中解构出来之后,两个变量的类型会被独立推导:
fn的类型推导为((arg: X) => void) | ((arg: Y) => void)arg的类型推导为'foo' | 'bar'
由于函数参数属于类型逆变位置,多个函数组成的联合类型,调用时的参数需要满足所有函数的参数要求,也就是所有参数类型的交集。'foo'和'bar'没有公共交集,交集类型就是never,所以你传入任何非never的参数都会报错,哪怕你逻辑上确定这两个值必然来自同一个联合分支,TS也不会做这种跨变量的关联校验。
解决方法
方法1:不解构,直接通过原对象调用
TS会识别同一个联合类型对象上的属性属于同一个分支,直接调用不会报错:
function acceptsUnion(union: DiscriminatedUnion): void { union.fn(union.arg); }
方法2:先根据可辨识字段收窄类型
如果你需要解构,可以先通过type字段做类型收窄,再在每个分支内解构使用:
function acceptsUnion(union: DiscriminatedUnion): void { if (union.type === 'X') { const {fn, arg} = union; fn(arg); // 类型匹配,无报错 } else { const {fn, arg} = union; fn(arg); // 类型匹配,无报错 } }
方法3:使用泛型约束
如果不想写分支判断,可以用泛型绑定联合类型的分支:
type UnionMap = { X: X, Y: Y } function acceptsUnion<T extends keyof UnionMap>(union: { type: T, fn: (arg: UnionMap[T]) => void, arg: UnionMap[T] }): void { const {fn, arg} = union; fn(arg); }
内容的提问来源于stack exchange,提问作者Андрей Фирсов
相关产品推荐
相关产品推荐

