TypeScript中if判断内联合类型未正确收窄是什么原因?
问题原因说明
这不是TypeScript的bug,属于当前类型收窄机制的设计限制。
核心逻辑
你写的if (r.loading === true || r.data instanceof Error)判断在逻辑上确实已经保证了r的类型满足ILoadingOrError['result']的要求,但TypeScript的类型收窄存在设计上的性能权衡:
类型守卫不会将类型收窄结果向上传播到父对象。收窄仅在访问被收窄的属性时生效,这就是为什么解构能正常工作,但直接引用父对象无法生效。对父对象进行收窄需要合成新类型,开销过高。
也就是说你对r.loading、r.data两个属性的收窄结果,只会作用于属性本身,不会自动更新整个r对象的类型,所以当你直接把整个r作为参数传递时,TS还是会用原始的Result类型做校验,因此触发类型不兼容报错。
可行解决方案
- 方案1:自定义类型守卫
主动定义类型收窄规则,让TS能识别整个对象的类型:function isLoadingOrError(r: Result): r is ILoadingOrError['result'] { return r.loading === true || r.data instanceof Error } // 使用时替换原有if判断 if (isLoadingOrError(r)) { y({result: r}); // 不会报错 } - 方案2:分支拆分构造对象
按联合类型的分支分别构造对象,触发TS的逐分支类型校验:if (r.loading === true || r.data instanceof Error) { y({ result: r.loading ? { loading: true } : { loading: false, data: r.data } }); } - 方案3:类型断言
确认逻辑无误的前提下,可以用类型断言跳过校验:y({result: r as ILoadingOrError['result']});
内容的提问来源于stack exchange,提问作者E-P
相关产品推荐
相关产品推荐

