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

泛型请求Effect类类型校验报错:返回Action无法被识别

泛型RequestEffect类中Action返回类型的TypeScript类型检查错误

问题描述

开发供其他类继承的泛型请求Effect类时,需传入三种Action类型实现泛型特性,但传递Action类型时触发TypeScript类型检查错误。代码可正常运行,但类型校验不通过,需明确为何返回的Action无法被正确识别。

代码示例

export interface ActionCreatorWithProps<TPropArgs extends object = {}>
  extends ActionCreator<string,
    (props: TPropArgs) => TPropArgs & TypedAction<string>
  > {
}

export interface EffectActions<S extends object, A extends object = {}, E extends object = {}> {
  startAction: ActionCreatorWithProps<A>;
  successAction: ActionCreatorWithProps<S>;
  errorAction: ActionCreatorWithProps<E>;
}

export abstract class RequestEffects<T extends object, A extends object = {}, E extends object = {}> {
///....
protected constructor(
    private requestEffectActions: RequestEffectActions<T, A>) {
}

makeRequestEffect$= createEffect(() =>
      this.actions$.pipe(
        ofType<ActionCreatorWithProps<A>>(this.requestEffectActions.startAction),
        concatMap(() => this.executeRequest().pipe(
            map((response) => {
              return this.requestEffectActions.successAction(response);

              // * 直接返回action实例(比如return myAction())正常
              // ** 断言为Action也不会报错
              // return this.requestEffectActions.successAction(response) as Action; 
            }),
          ),
        ))
    );
}

错误信息

TS2322: Type 'Observable<T & TypedAction<string>>' is not assignable to type 'Observable<T & TypedAction<string>> & (T & TypedAction<string> extends ActionCreator<string, Creator<any[], object>> ? "ActionCreator cannot be dispatched. Did you forget to call the action creator function?" : unknown)'. 
  Type 'Observable<T & TypedAction<string>>' is not assignable to type 'T & TypedAction<string> extends ActionCreator<string, Creator<any[], object>> ? "ActionCreator cannot be dispatched. Did you forget to call the action creator function?" : unknown'.  effect_creator.d.ts(12, 103): The expected type comes from the return type of this signature.

原因分析

错误源于createEffect的返回类型约束——它内置了一个条件类型,用于检查开发者是否误返回了ActionCreator函数而非Action实例。

由于类使用了泛型T,编译时TypeScript无法确定T & TypedAction<string>是否会意外匹配ActionCreator的类型签名。尽管实际调用successAction(response)返回的是Action实例,但泛型的不确定性让TypeScript触发了条件类型的错误分支,误判为可能返回了未调用的ActionCreator。

解决方案

方案1:显式约束泛型T不能是ActionCreator

在泛型参数中排除ActionCreator类型,让TypeScript明确T的范围:

// 定义类型,排除所有ActionCreator类型
type NotActionCreator = object & { [K in keyof ActionCreator<string, any>]?: never };

export abstract class RequestEffects<T extends NotActionCreator, A extends object = {}, E extends object = {}> {
  // ... 其余代码不变
}

此方式能让TypeScript确定T & TypedAction<string>不可能是ActionCreator,条件类型会直接走正确分支。

方案2:安全的类型断言

若不想修改泛型约束,可在返回时使用更精确的类型断言,替代宽泛的as Action:

map((response) => {
  return this.requestEffectActions.successAction(response) as ReturnType<typeof this.requestEffectActions.successAction>;
}),

该断言基于实际的successAction返回类型,比直接断言为Action更安全。

方案3:调整EffectActions的泛型定义

明确指定successAction的返回类型为Action,避免依赖泛型推导:

export interface EffectActions<S extends object, A extends object = {}, E extends object = {}> {
  startAction: ActionCreatorWithProps<A>;
  successAction: (props: S) => S & TypedAction<string> & Action; // 显式混入Action接口
  errorAction: ActionCreatorWithProps<E>;
}

此方式能让TypeScript直接识别返回值为Action实例,消除条件类型的歧义。


内容的提问来源于stack exchange,提问作者Diego

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 16:10:25