TypeScript联合类型收窄失效,无需额外类型守卫的解决方案有哪些?
问题原因
TypeScript 的类型收窄不会自动跟踪多个独立变量之间的类型关联。你在分支中分别给f赋值后,f的最终类型会被推导为((x: A) => number) | ((x: B) => number),arg的类型是A | B,二者的类型是完全独立的,编译器无法确认f的入参类型一定和当前arg的类型匹配,因此抛出类型错误。
可行解决方案(无需额外新增类型守卫)
1. 把applyFunc调用移到每个分支内部
这是最安全、不需要额外类型操作的方案。每个分支内部arg和f的类型已经被收窄为完全匹配的对应类型,直接调用即可:
const doTheThing = (arg : A | B) => { if (isAnA(arg)) { const f = (x : A) => x.a * 2; return applyFunc(f, arg); } else { const f = (x : B) => parseInt(x.b) * 2; return applyFunc(f, arg); } }
2. 显式声明f的兼容类型
你可以提前给f声明为可接收联合类型入参的函数类型,编译器就不会报错:
const doTheThing = (arg : A | B) => { let f: (x: A | B) => number; if (isAnA(arg)) { f = (x : A) => x.a * 2; } else { f = (x : B) => parseInt(x.b) * 2; } return applyFunc(f, arg); }
由于函数参数是逆变的,接收单个A/ B类型入参的函数可以赋值给接收A | B入参的函数类型,因此这个声明是完全合法的。
3. 用类型断言跳过校验(不推荐,仅做参考)
如果你确认逻辑没有问题,也可以直接用类型断言强制编译器通过校验,不过这种方式跳过了类型检查,有安全隐患:
const doTheThing = (arg : A | B) => { let f; if (isAnA(arg)) { f = (x : A) => x.a * 2; } else { f = (x : B) => parseInt(x.b) * 2; } return applyFunc(f as (x: A | B) => number, arg); }
内容的提问来源于stack exchange,提问作者Davis Yoshida
相关产品推荐
相关产品推荐

