TypeScript严格模式下如何正确区分非重叠属性接口
嘿,这个场景我太熟悉了!严格模式下TypeScript对联合类型的属性访问限制确实挺严格的,不过不用自定义类型守卫也有规范的解决办法,我给你分享两种最常用的:
1. 用in操作符(最推荐)
这是TypeScript原生支持的类型守卫写法,直接检查属性是否存在于对象中,TS会自动帮你缩小变量的类型范围,完全符合严格模式要求:
const variable: { a: string } | { b: number }; if ('a' in variable) { // 到这里TS已经自动推断variable是{ a: string }类型了 console.log(variable.a.toUpperCase()); } else { // 这里则自动推断为{ b: number }类型 console.log(variable.b.toFixed(2)); }
之所以这个写法能行,是因为in操作符只是检查属性是否存在,不会提前去访问variable.a(这正是之前你直接写variable.a !== undefined报错的原因——TS不允许访问联合类型中部分成员没有的属性)。
2. 用Object.prototype.hasOwnProperty.call
如果你更倾向于检查对象自身是否拥有该属性(而非继承来的),可以用这个写法,TS 2.7+版本也会把它当作类型守卫:
const variable: { a: string } | { b: number }; if (Object.prototype.hasOwnProperty.call(variable, 'a')) { console.log(variable.a); // 这里同样会被推断为{ a: string }类型 }
不过这个写法比in繁琐一些,日常场景用in就足够了。
顺便说下为什么你之前尝试的写法都不行:不管是variable.a !== undefined还是typeof variable.a !== 'undefined',本质上都是先去访问了variable.a这个可能不存在的属性,严格模式下TS会直接抛出错误,根本到不了判断逻辑那一步;而直接用variable.hasOwnProperty('a')也会报错,因为TS不确定联合类型的所有成员都有hasOwnProperty方法(虽然实际运行时对象都有,但TS严格模式下不认这个),所以必须用Object.prototype.hasOwnProperty.call的形式来绕开。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

