Redux结合TypeScript定义Action联合类型触发类型循环引用报错
报错触发原因
这个循环引用报错的本质是类型推导链路形成了闭合的死循环,触发链路如下:
- 你定义
Action联合类型时,将ReturnType<typeof addToCart>纳入了成员范围。而addToCart是一个符合redux-thunk规范的高阶函数,调用后并不会直接返回传给reducer的纯action对象,而是返回一个带dispatch、getState入参的异步函数(也就是thunk本体)。 - 这个返回的thunk函数类型,依赖
getState: () => RootState的类型标注。 - 项目中的
RootState类型通常是聚合所有reducer的状态推导出来的,而每个reducer的入参类型,恰好又是你当前正在定义的这个Action联合类型。 - 类型推导流程走到这就形成了闭环:
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
相关产品推荐
相关产品推荐

