TypeScript可辨识联合在React reducer中报payload属性不存在错误
错误产生原因
你写的可辨识联合不满足TypeScript的类型缩窄要求,核心问题出在Action类型的定义上:
- 可辨识联合的判别属性(这里是
type字段)必须使用精确的字符串字面量类型,不能写宽泛的string。你现在两个联合分支的type字段类型都是string,TS根本没法通过action.type的具体值判断当前命中了哪个联合分支,自然做不了类型缩窄。 - 两个联合分支的属性不统一:只有第一个分支声明了
payload属性,第二个分支{ type: string }完全没有payload字段。TS在没法确定具体分支类型的时候,只允许访问所有分支共有的属性,payload不是公共属性,访问时就会抛出不存在的错误。 - 额外提一句,你把带payload分支的payload类型写成
AuthState也不合理,AuthState是整个认证状态的结构,登录成功动作的payload只需要返回用户信息和token就行,不需要完整的状态结构。
修复方案
把每个Action分支的type改成和case里对应的精确字符串字面量,同时明确每个动作对应的payload结构,不需要payload的分支就不要声明payload字段,修改后的代码如下:
// 定义登录成功动作携带的payload结构,也可以直接内联在类型定义里 type LoginSuccessPayload = { user: { id: string; name: string; email: string }; access_token: string; } export type Action = | { type: "LOGIN_SUCCESS"; payload: LoginSuccessPayload; } | { type: "LOGOUT"; };
改完之后TypeScript会在switch语句里自动根据action.type做类型缩窄:
- 进入
case "LOGIN_SUCCESS"分支时,TS会自动判定当前action是带payload的分支,可以安全访问action.payload.user、action.payload.access_token,不会再报类型错误 - 进入
case "LOGOUT"分支时,TS会判定当前action是无payload的分支,如果你误写了访问payload的代码还会主动提示错误 - 原reducer里default分支抛错的逻辑可以保留,属于reducer编写的最佳实践,能拦截未定义的非法action。
内容的提问来源于stack exchange,提问作者B L Praveen
相关产品推荐
相关产品推荐

