TypeScript联合类型赋值判别属性后访问独有属性为何报错
TypeScript联合类型判别属性收窄行为差异问题
问题现象
在使用类型别名定义联合类型时,即便显式为变量赋值了判别属性的对应值,TypeScript仍会对访问仅存在于联合类型某一成员类型上的属性报类型错误;但将同类型变量传入函数,在函数内通过判别属性做类型收窄后访问对应独有属性,却不会触发类型报错,具体复现示例如下:
基础示例代码:
interface I1{ type: "1" commonProp: any uniqueFor1: any } interface I2{ type: "2" commonProp: any uniqueFor2: any } interface I3{ type: "3" commonProp: any uniqueFor3: any } type typeX = (I1 | I2 | I3) let somevar = {} as typeX somevar.type = "1"
执行如下操作时会触发类型报错:
somevar.uniqueFor1 = " i am 1"
但如下写法却可正常通过类型校验:
function test(x: typeX) { switch (x.type) { case "1": x.uniqueFor1 = "i am 1" break; case "2": x.uniqueFor2 = "i am 2" break; case "3": x.uniqueFor3 = "i am 2" break; } } test(somevar)
根本原因
两者的行为差异是TypeScript类型收窄的规则边界决定的:
as类型断言的本质是手动强制指定变量的静态类型,不会触发TS的自动类型推导调整。写let somevar = {} as typeX之后,somevar的类型就被固定为完整联合类型I1 | I2 | I3,后续单独给somevar.type = "1"赋值的操作,不会让TS把变量类型收窄为I1。对于let声明的可变变量,TS不会将单次属性赋值作为收窄依据——毕竟这个属性的值随时可能在其他代码逻辑里被修改为"2"或"3",TS无法追踪所有执行路径上的修改,贸然收窄会破坏类型检查的可靠性。- 函数内的switch分支判断属于TS原生支持的*可辨识联合(Discriminated Union)*收窄场景:在函数的局部作用域中,参数
x是局部绑定的,当通过switch对x.type做精确等值匹配时,TS可以确定每个case分支内x.type的固定值,对应就能将x收窄为联合类型中匹配该判别值的具体成员,这时候访问对应成员的独有属性自然不会触发类型错误。 - 核心逻辑可以总结为:TS的控制流类型收窄只会在「能确保判断后类型不会被意外修改」的安全场景生效,函数内的分支判断属于这类场景;而外层let变量先通过断言标记为联合类型、再单独修改判别属性的写法,TS无法保证后续执行流中类型的稳定性,因此不会做自动收窄。
内容的提问来源于stack exchange,提问作者A Kam
相关产品推荐
相关产品推荐

