You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 00:12:34