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

Redux结合TypeScript定义Action联合类型触发类型循环引用报错

报错触发原因

这个循环引用报错的本质是类型推导链路形成了闭合的死循环,触发链路如下:

  1. 你定义Action联合类型时,将ReturnType<typeof addToCart>纳入了成员范围。而addToCart是一个符合redux-thunk规范的高阶函数,调用后并不会直接返回传给reducer的纯action对象,而是返回一个带dispatch、getState入参的异步函数(也就是thunk本体)。
  2. 这个返回的thunk函数类型,依赖getState: () => RootState的类型标注。
  3. 项目中的RootState类型通常是聚合所有reducer的状态推导出来的,而每个reducer的入参类型,恰好又是你当前正在定义的这个Action联合类型。
  4. 类型推导流程走到这就形成了闭环:Action 要解析 thunk 的类型 → thunk 要解析 RootState 的类型 → RootState 要解析 reducer 的参数类型 → reducer 参数要解析正在定义的Action类型,TS 无法跳出这个循环完成推导,就会抛出“circularly references itself”的报错。

另外这里还有个认知偏差:thunk 函数本身是被 redux-thunk 中间件拦截处理的,根本不会流到 reducer 逻辑里,本来就不该出现在给 reducer 用的 Action 联合类型中——你要收进联合类型的,是 thunk 内部手动 dispatch 给 reducer 的那些纯 action 对象。

对应修复方法
  • 从 Action 联合类型中移除 thunk creator 的返回值,仅保留真正会被传入 reducer 的纯 action 类型:
    • 对于像removeItem这样的同步纯 action creator,它的返回值本身就是合法的纯 action 对象,可以直接用ReturnType<typeof removeItem>提取类型。
    • 对于像addToCart这样的异步 thunk creator,不要直接把它的返回值纳入联合类型,而是单独定义它内部 dispatch 出去的CARD_ADD_ITEM对应的纯 action 类型。
  • 按照上面的规则修正后的 Action 类型示例:
// 仅包含会被 reducer 处理的纯 action 类型
export type CartAction =
  | ReturnType<typeof removeItem>
  | {
      type: typeof CartActionTypes.CARD_ADD_ITEM;
      payload: {
        id: string;
        name: string;
        image: string;
        price: number;
        countInStock: number;
        qty: number;
      };
    };
  • 如果需要给 thunk 函数本身做类型标注,可以单独使用 redux-thunk 官方提供的ThunkAction类型来定义,不要把它和普通 reducer 接收的 Action 类型混为一谈。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 06:36:03