NgRx中在Action Props里传递引用Action的正确类型是什么?
问题
我的应用中有多个父实体共享的模型(如电话号码、地址、电子邮箱)。在共享地址组件中,我希望将用户特定的成功和失败Action传递给Effect,由Effect触发这些作为Props传入的Action,再由用户侧的Reducer和Effect处理以更新Store、显示通知。
现有代码可正常运行,但我不想将Effect结果强制转换为Action<string>,请问onSuccess和onFailure的正确类型是什么?
代码示例
// 通用地址更新action export const dispatchUpdateAddress = createAction( "Change generic address object", props<{ payload: any, onSuccess: ActionCreator, onFailure: ActionCreator }>() ); // 地址所属用户实体的特定成功action export const dispatchUserAddressUpdateSuccess = createAction( "Do user specific thing on success", props<{ payload: any }>() ); // 地址所属用户实体的特定失败action export const dispatchUserAddressUpdateFailure = createAction( "Do user specific thing on failure", props<{ payload: any }>() ); export class AddressEffects { updateAddress$ = createEffect(() => this.actions$.pipe( ofType(dispatchUpdateAddress), mergeMap((action) => this.dataService.update$(action.data).pipe( map((res) => action.onSuccess(res.payload) as unknown as Action<string>), catchError((res) => of(action.onFailure(res) as unknown as Action<string>)) ) ) ) ); } // 组件实现 export class SharedAddressComponent { updateAddress(payload: {address1: string, address2: string}) { this.store.dispatch(dispatchUpdateAddress({ payload, // 将在user.effects中处理 onSuccess: dispatchUserAddressUpdateSuccess, onFailure: dispatchUserAddressUpdateFailure })) } }
解决方案
你可以利用NgRx的ActionCreator泛型类型,结合返回的Action类型准确定义onSuccess和onFailure,彻底避免强制类型转换。
1. 修正通用Action的类型定义
将dispatchUpdateAddress的props类型中的onSuccess和onFailure指定为接收特定payload并返回对应Action的ActionCreator,同时建议替换any为具体类型提升安全性:
import { ActionCreator, props, createAction } from '@ngrx/store'; import { Action } from '@ngrx/store'; // 定义具体的payload和响应类型(替换any) type AddressPayload = { address1: string, address2: string }; type UpdateSuccessData = any; // 根据实际接口返回值定义 type UpdateError = any; // 根据实际错误结构定义 export const dispatchUpdateAddress = createAction( "Change generic address object", props<{ payload: AddressPayload, onSuccess: ActionCreator<string, (props: { payload: UpdateSuccessData }) => Action<string>>, onFailure: ActionCreator<string, (props: UpdateError) => Action<string>> }>() );
2. 移除Effect中的类型断言
此时TypeScript会自动推导返回的Action类型,无需再做强制转换:
export class AddressEffects { updateAddress$ = createEffect(() => this.actions$.pipe( ofType(dispatchUpdateAddress), mergeMap((action) => this.dataService.update$(action.payload).pipe( map((res) => action.onSuccess({ payload: res.payload })), catchError((error) => of(action.onFailure(error))) ) ) ) ); }
3. 可选优化:泛型化通用Action
如果需要让dispatchUpdateAddress支持不同类型的payload和响应,可以将其改为泛型Action,进一步提升通用性:
export const dispatchUpdateAddress = <TPayload, TSuccess, TError>(type: string) => createAction( type, props<{ payload: TPayload, onSuccess: ActionCreator<string, (props: { payload: TSuccess }) => Action<string>>, onFailure: ActionCreator<string, (props: TError) => Action<string>> }>() ); // 使用时指定具体类型 export const updateUserAddress = dispatchUpdateAddress<AddressPayload, UpdateSuccessData, UpdateError>( "Change generic address object" );
这样既保留了代码的复用性,又完全消除了不必要的类型转换,同时让类型检查更严谨。
内容的提问来源于stack exchange,提问作者Tom Ford
相关产品推荐
相关产品推荐

