TypeScript如何编写可校验接口属性类型的类型守卫
报错原因
这个报错的核心问题出在对象判断逻辑和类型收窄顺序上:
value instanceof Object不是可靠的对象校验逻辑:Object.create(null)生成的无原型对象、跨iframe/Realm创建的纯对象都会被判定为false,不符合「传入值为对象类型」的校验需求;同时TypeScript对unknown类型做instanceof Object收窄时,和后续in操作符的收窄逻辑存在冲突,会导致in判断后value被意外推导为never类型,自然无法访问任何属性。- 没有先将
unknown类型收窄为明确的object类型就直接做属性存在性校验,TS无法推导该值上允许挂载自定义属性。
正确实现
按照类型收窄的顺序依次完成三层校验即可,推荐用更可靠的逻辑替代instanceof Object:
interface Person { name: string; } const isPerson = (value: unknown): value is Person => { // 第一步:校验为非空对象,排除原始值、null、undefined if (typeof value !== 'object' || value === null) { return false } // 此处TS已将value收窄为object类型,可安全使用in操作符 // 第二步:校验存在name属性 if (!('name' in value)) { return false } // 此处TS已推导value包含类型为unknown的name属性,可安全访问 // 第三步:校验name属性为string类型 return typeof value.name === 'string' }
如果偏好单行箭头函数的写法,只要调整判断顺序、替换不可靠的instanceof判断也可正常运行:
const isPerson = (value: unknown): value is Person => ( typeof value === 'object' && value !== null && 'name' in value && typeof value.name === 'string' )
逻辑说明
TypeScript会跟随判断逻辑自动做类型收窄:
- 经过
typeof value === 'object' && value !== null判断后,value类型从unknown收窄为object - 经过
'name' in value判断后,value类型收窄为object & { name: unknown },访问value.name不会触发类型错误 - 最后通过
typeof value.name === 'string'校验后,完全匹配Person接口的结构,类型守卫生效。
如果需要校验更复杂的嵌套接口,沿用逐层收窄的逻辑即可,不需要额外加类型断言。
内容的提问来源于stack exchange,提问作者slifty
相关产品推荐
相关产品推荐

