TypeScript对联合类型推断出never类型的原因解析
你的代码里出现这个问题,核心在于**BarEntity的类型定义本质上和BaseEntity完全等价**,导致TypeScript对联合类型的收窄逻辑和你预期的不一样。
关键细节拆解
类型等价性
你定义的BarEntity = BaseEntity & {},交叉一个空对象不会给原类型添加任何属性或约束,所以*BarEntity和BaseEntity*是完全相同的类型。联合类型的简化
Entity = FooEntity | BarEntity实际上会被TypeScript简化为FooEntity | BaseEntity。但因为*FooEntity是BaseEntity的子类型(它继承了BaseEntity的所有属性,还多了additionalData),所以整个联合类型最终会被进一步简化为BaseEntity*——因为任何FooEntity实例都符合BaseEntity的类型约束。类型守卫的影响
当你用isBarType(value)进行判断时,这个类型守卫断言value是*BarEntity(也就是BaseEntity)。由于Entity本质上就是BaseEntity,TypeScript会认为所有可能的Entity实例都满足isBarType的断言,所以在if分支之外,没有剩余的类型可以匹配,自然推断为never*。
为什么反向校验能生效?
当你用isFooType判断时,这个守卫明确区分了*FooEntity和其他BaseEntity实例。TypeScript能识别出:符合isFooType的是FooEntity,不符合的是普通BaseEntity(也就是你原本想表达的BarEntity*),所以收窄逻辑能正常工作。
修复方案
要让类型收窄符合你的预期,需要让*BarEntity和BaseEntity产生明确的类型差异,比如给BarEntity*添加一个独特的属性:
type BarEntity = BaseEntity & { type: 'bar'; // 添加区分属性 };
或者调整类型守卫的逻辑,直接针对*FooEntity*的特征进行判断:
function isFooType(value: Entity): value is FooEntity { return 'additionalData' in value; }
内容的提问来源于stack exchange,提问作者someRandomDev

