TypeScript类型包含目标属性仍报属性不存在如何解决
报错原因
这个TS2339错误本质是类型收窄未生效:
- 你手动给
payload标注了AnyEventPayload类型,这是多成员联合类型,TS默认不会将message_type的等值判断和payload的类型分支做关联。 - 即使你判断了
message_type === 'idCheck.applicantStatus',TS也无法自动推断出此时的payload就是带reviewStatus字段的那个联合分支,因此会判定你访问了联合类型上不一定存在的属性,抛出错误。 - 你写的处理函数完全没有用到
MessageHandler定义里的泛型推导能力,主动把payload类型写成了宽泛的全量联合类型,是触发这个问题的直接原因。
修复方法
按推荐优先级从高到低排列:
方法1:使用MessageHandler类型约束函数,放弃手动标注入参类型
这是最贴合原类型设计的写法,不需要额外写类型断言或判断,TS会自动完成类型推导和收窄:const msgHandler: MessageHandler = (message_type, payload) => { console.log(message_type, payload) if (message_type === 'idCheck.applicantStatus' && payload.reviewStatus === 'completed') { router.push('/') } }原
MessageHandler本身就是带泛型的函数类型,当你对message_type做字面量等值判断时,TS会自动将payload收窄到对应事件的payload类型,直接访问reviewStatus不会触发报错。方法2:通过in操作符手动收窄类型
如果你一定要手动标注入参类型,可以在事件名判断的分支内,先校验目标属性存在,触发TS的类型收窄:(message_type: AnyEventName, payload: AnyEventPayload) => { console.log(message_type, payload) if (message_type === 'idCheck.applicantStatus') { if ('reviewStatus' in payload && payload.reviewStatus === 'completed') { router.push('/') } } }in操作符会告诉TS,当前分支的payload一定包含reviewStatus属性,会自动匹配到联合类型中对应结构的分支,消除属性不存在的报错。方法3:使用类型断言(不推荐)
赶时间的场景下可以直接指定分支内payload的类型,绕过TS的检查:(message_type: AnyEventName, payload: AnyEventPayload) => { console.log(message_type, payload) const statusPayload = payload as Extract<AnyEventPayload, { reviewStatus: string }> if (message_type === 'idCheck.applicantStatus' && statusPayload.reviewStatus === 'completed') { router.push('/') } }这种写法会丢失类型校验能力,如果后续事件的payload结构变更,TS不会给出提示,容易引入线上问题,非必要不使用。
不要为了快速消错直接将payload标注为
any,会完全关闭该位置的类型检查,后续出现属性名拼写错误、字段取值错误都不会有提示。
内容的提问来源于stack exchange,提问作者sev
相关产品推荐
相关产品推荐

