TypeScript 2.7.1+NgRx中Reducer报Property不存在类型错误的修复方案
解决NgRx + TypeScript 2.7.1中Action Payload的类型错误问题
我之前在使用NgRx早期版本配合TypeScript 2.x时也遇到过完全一样的问题——不想把payload设成any破坏类型安全,但总是碰到“Property does not exist on type”的报错。核心问题在于没有正确利用**区分联合类型(discriminated union)**让TypeScript识别不同Action的payload结构,下面是具体的修复方案:
第一步:给Action定义明确的类型和结构
首先要放弃模糊的通用Action写法,为每个Action创建独立的类,并合并成联合类型:
import { Action } from '@ngrx/store'; // 1. 定义Action类型常量(建议用域前缀避免冲突) export const LOAD_USER = '[User] Load User'; export const LOAD_USER_SUCCESS = '[User] Load User Success'; // 2. 定义payload的类型接口(如果Action需要payload的话) export interface UserPayload { id: number; name: string; email: string; } // 3. 为每个Action创建实现Action接口的类 export class LoadUser implements Action { readonly type = LOAD_USER; // 这个Action没有payload,所以不需要额外属性 } export class LoadUserSuccess implements Action { readonly type = LOAD_USER_SUCCESS; // 用构造函数public属性自动生成payload,明确类型 constructor(public payload: UserPayload) {} } // 4. 把所有Action合并成联合类型——这是关键! export type UserActions = LoadUser | LoadUserSuccess;
第二步:在Reducer中使用联合类型约束Action
Reducer的action参数必须指定为上面的联合类型UserActions,而不是宽泛的Action接口。这样TypeScript会根据action.type自动缩小类型范围,正确识别payload的存在和类型:
import { UserActions, LOAD_USER, LOAD_USER_SUCCESS } from './user.actions'; import { UserPayload } from './user.actions'; // 定义状态的类型 export interface UserState { currentUser: UserPayload | null; isLoading: boolean; } const initialState: UserState = { currentUser: null, isLoading: false, }; // 这里action的类型是UserActions,不是Action! export function userReducer(state = initialState, action: UserActions): UserState { switch (action.type) { case LOAD_USER: return { ...state, isLoading: true, }; case LOAD_USER_SUCCESS: // 此时TypeScript明确知道这是LoadUserSuccess类型,payload存在且是UserPayload return { ...state, isLoading: false, currentUser: action.payload, }; default: return state; } }
为什么之前会报错?
如果你的Reducer里action用的是Action接口,TypeScript只知道它有type属性,无法确定某个具体type对应的Action是否有payload,自然会提示“payload不存在”。而联合类型配合readonly的type属性,会让TypeScript把type当成类型区分符,在switch的每个case里自动推断出对应的Action类型,从而正确识别payload。
额外注意事项
- 确保每个Action类的
type属性是readonly的,这样TypeScript才能把它作为联合类型的区分标识。 - 不要给payload设为可选类型(比如
payload?: UserPayload),除非这个Action确实可能没有payload,否则会导致TypeScript推断payload可能为undefined,依然会报错。 - 如果有多个Action的payload类型不同,只要每个Action类都明确自己的payload类型,联合类型会自动处理类型缩小。
内容的提问来源于stack exchange,提问作者that_guy
相关产品推荐
相关产品推荐

