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

使用redux-actions重构TypeScript计数器示例遇错求助

问题描述

我是TypeScript新手,想要练习redux-actions库。先是跟着YouTube教程和redux-actions官方教程学习,但官方教程示例在jsfiddle或codepen中无法运行,于是决定修改YouTube教程的GitHub代码库,引入redux-actions库。

编写actions和reducer组件时遇到两个问题:

  1. increment和decrement出现错误提示「A computed property name must be of type 'string', 'number', 'symbol', or 'any'.ts(2464)」
  2. 不确定payload用any类型是否合适,有没有更好的类型定义方式

以下是我的代码尝试:

Counter.ts

export interface Counter {
    count: number;
}

CounterActions.ts

import { createActions } from "redux-actions";

export const { increment, decrement } = createActions({
  INCREMENT: (amount = 1) => ({ amount }),
  DECREMENT: (amount = 1) => ({ amount: -amount }),
});

interface IncrementAction {
  type: typeof increment;
}

interface DecrementAction {
  type: typeof decrement;
}

export type CounterActionTypes = IncrementAction | DecrementAction;

CounterReducer.ts

import { handleActions } from "redux-actions";

import { CounterActionTypes, decrement, increment } from "./CounterAction";
import { Counter } from "./models/Counter";

const defaultState: Counter = {
  count: 0,
};

export const counterReducer = handleActions(
  {
    [increment]: (state: Counter, { payload: { amount } }: any): Counter => {
      return { ...state, count: state.count + amount };
    },
    [decrement]: (state: Counter, { payload: { amount } }: any): Counter => {
      return { ...state, count: state.count + amount };
    },
  },
  defaultState
);

问题修复方案

1. 解决计算属性类型错误

increment和decrement是redux-actions生成的action creator函数,不能直接作为对象的计算属性名。需要通过toString()方法获取对应的action type字符串,或者直接使用定义的常量名。

方案一:使用action creator的toString()方法

修改后的CounterReducer.ts:

import { handleActions } from "redux-actions";

import { decrement, increment } from "./CounterAction";
import { Counter } from "./models/Counter";

const defaultState: Counter = {
  count: 0,
};

export const counterReducer = handleActions(
  {
    [increment.toString()]: (state: Counter, { payload: { amount } }) => {
      return { ...state, count: state.count + amount };
    },
    [decrement.toString()]: (state: Counter, { payload: { amount } }) => {
      return { ...state, count: state.count + amount };
    },
  },
  defaultState
);

方案二:直接使用action type常量

先在CounterActions.ts中导出type常量:

import { createActions } from "redux-actions";

const actions = createActions({
  INCREMENT: (amount = 1) => ({ amount }),
  DECREMENT: (amount = 1) => ({ amount: -amount }),
});

export const { increment, decrement } = actions;
// 导出action type常量
export const { INCREMENT, DECREMENT } = actions.types;

然后在CounterReducer.ts中使用:

import { handleActions } from "redux-actions";

import { DECREMENT, INCREMENT } from "./CounterAction";
import { Counter } from "./models/Counter";

const defaultState: Counter = {
  count: 0,
};

export const counterReducer = handleActions(
  {
    [INCREMENT]: (state: Counter, { payload: { amount } }) => {
      return { ...state, count: state.count + amount };
    },
    [DECREMENT]: (state: Counter, { payload: { amount } }) => {
      return { ...state, count: state.count + amount };
    },
  },
  defaultState
);

2. 优化payload的类型定义

避免使用any类型,有两种常用的类型定义方式:

方法一:手动定义payload类型并结合redux-actions的Action类型

修改CounterActions.ts:

import { createActions, Action } from "redux-actions";

// 定义payload类型
interface AmountPayload {
  amount: number;
}

export const { increment, decrement } = createActions({
  INCREMENT: (amount = 1): AmountPayload => ({ amount }),
  DECREMENT: (amount = 1): AmountPayload => ({ amount: -amount }),
});

// 定义完整的action类型
export type IncrementAction = Action<AmountPayload>;
export type DecrementAction = Action<AmountPayload>;

export type CounterActionTypes = IncrementAction | DecrementAction;

然后在Reducer中指定action类型:

[increment.toString()]: (state: Counter, action: IncrementAction): Counter => {
  return { ...state, count: state.count + action.payload.amount };
},
[decrement.toString()]: (state: Counter, action: DecrementAction): Counter => {
  return { ...state, count: state.count + action.payload.amount };
},

方法二:通过ReturnType推导payload类型

在CounterActions.ts中添加类型推导:

import { createActions } from "redux-actions";

export const { increment, decrement } = createActions({
  INCREMENT: (amount = 1) => ({ amount }),
  DECREMENT: (amount = 1) => ({ amount: -amount }),
});

// 推导payload类型
export type IncrementPayload = ReturnType<typeof increment>['payload'];
export type DecrementPayload = ReturnType<typeof decrement>['payload'];

在Reducer中使用推导的类型:

[increment.toString()]: (state: Counter, action: { payload: IncrementPayload }) => {
  return { ...state, count: state.count + action.payload.amount };
},
[decrement.toString()]: (state: Counter, action: { payload: DecrementPayload }) => {
  return { ...state, count: state.count + action.payload.amount };
},

免费学习资源推荐
  • redux-actions官方文档:虽然示例在在线编辑器无法运行,但文档的API说明和用法逻辑很清晰,结合本地项目测试更高效
  • TypeScript官方手册的Redux相关章节:讲解了TypeScript结合Redux的类型最佳实践
  • YouTube实战教程:搜索"TypeScript redux-actions tutorial",选择近期更新、播放量较高的视频,跟着本地敲代码测试
  • 开源项目参考:在GitHub搜索"redux-actions typescript",查看成熟项目中action和reducer的写法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:43:29