为何Action Creator含type属性?如何避免其被误作为参数传入?
问题
我写了一个接受Action数组的函数,Action类型仅要求具备type属性。测试时误将Action Creator直接传入而非调用它的返回结果,导致测试失败。排查后发现TypeScript未报错——因为BaseActionCreator同样拥有type属性,使得二者在TypeScript中可互换传入,但这并非我期望的行为。请问:
- Action Creator设置
type属性有特殊原因吗? - 有没有办法阻止Action Creator被作为参数传入?
示例代码:
import { Action, createAction } from "@reduxjs/toolkit"; function myFunction(actions: Action[]) { actions.forEach((action) => console.log(action.type)); } const customActionCreator = createAction("CUSTOM"); myFunction([customActionCreator()]); // 正确调用 myFunction([customActionCreator]); // 错误传入,但TypeScript未报错
回答
1. Action Creator设置type属性的原因
Redux Toolkit的createAction生成的Action Creator携带type属性,核心原因是为了提升开发效率和生态兼容性:
- 避免硬编码字符串:可以直接通过
customActionCreator.type引用action类型,无需额外定义常量,减少拼写错误。 - 支持类型自动推断:Redux Toolkit内部依赖这个属性生成Action的类型定义,让TypeScript能正确识别action的结构。
- 适配Redux生态工具:部分中间件、调试工具会读取该属性,关联Action Creator与对应的action类型,优化调试体验。
2. 阻止Action Creator被误传入的方法
通过严格定义Action类型,让它与Action Creator类型明确区分,即可触发TypeScript报错拦截:
方法一:自定义严格Action类型
扩展Redux的Action类型,添加一个仅用于类型区分的标记属性:
import { Action, createAction } from "@reduxjs/toolkit"; // 定义严格的Action类型,排除函数类型 type StrictAction<T extends string = string> = Action<T> & { // 空属性仅用于类型区分,不影响运行时 _isAction?: never; }; function myFunction(actions: StrictAction[]) { actions.forEach((action) => console.log(action.type)); } const customActionCreator = createAction("CUSTOM"); myFunction([customActionCreator()]); // 正常通过 myFunction([customActionCreator]); // TypeScript报错:类型不匹配
方法二:使用Redux Toolkit内置的PayloadAction
如果你的action无payload,可使用PayloadAction<void>明确区分Action与Action Creator:
import { PayloadAction, createAction } from "@reduxjs/toolkit"; function myFunction(actions: PayloadAction<void>[]) { actions.forEach((action) => console.log(action.type)); } const customActionCreator = createAction("CUSTOM"); myFunction([customActionCreator()]); // 正常通过 myFunction([customActionCreator]); // TypeScript报错
方法三:添加运行时类型守卫
在函数内部增加校验逻辑,同时辅助TypeScript类型推断,即使编译期漏检也能在运行时快速发现问题:
import { Action, createAction } from "@reduxjs/toolkit"; function isAction(action: unknown): action is Action { return typeof action === "object" && action !== null && "type" in action && typeof (action as Action).type === "string"; } function myFunction(actions: Action[]) { actions.forEach((action) => { if (!isAction(action)) { throw new Error("传入的不是有效的Action"); } console.log(action.type); }); } const customActionCreator = createAction("CUSTOM"); myFunction([customActionCreator()]); // 正常执行 myFunction([customActionCreator]); // 运行时抛出错误
内容的提问来源于stack exchange,提问作者Juan De la Cruz
相关产品推荐
相关产品推荐

