Search code examples
reactjstypescriptreduxreact-redux

How to structure a react-redux reducer with Typescript to handle different kinds of payloads?


So, I'm trying to build a Todo App with react, redux and typescript. There are going to be some todo pages and each page will involve todos.

Below are the necessary types and the Todos state.

export type Todo = {
  name: string;
  due: Date;
  color: string;
  pageId: string;
};

export type TodosByPageId = {
  [page: string]: Todo[];
}

export type TodosState = {
  byPageId: TodosByPageId;
  curPageId: string;
};

After defining my constants and actions I export below given actions for the reducer:

export type TodosAction = SetTodos | AddTodo | DeleteTodo | UpdateTodo | SetTodoPageId;

Basically

  • AddTodo, DeleteTodo and UpdateTodo takes a todo and payload is a Todo
  • SetTodos takes Todo[] and payload is Todo[]
  • SetTodoPageId takes string and payload is string

Then I started defining the todosReducer:

const initalState: TodosState = {
  byPageId: {},
  curPageId: '',
}

const todosReducer = (state: TodosState, action: TodosAction): TodosState => {
  switch(action.type) {
    case Constants.ADD_TODO:
      return state; // TODO
    case Constants.DELETE_TODO:
      return state; // TODO
    case Constants.SET_TODOS:
      return state; // TODO
    case Constants.SET_TODO_PAGE_ID:
      return { ...state, curPageId: action.payload };
    case Constants.UPDATE_TODO:
      return state; // TODO
    default:
      return state;
  }
}

At the line I handled SET_TODO_PAGE_ID gave me the error

Type 'string | Todo | Todo[]' is not assignable to type 'string'.
  Type 'Todo' is not assignable to type 'string'.

which makes sense. Typecasting in each case didn't seem right, so I wanted to ask what would be a better design for these kinds of situations?

By the way, I know redux toolkit is the suggested way, but I'm just trying to learn both styles.


Solution

  • I'm a Redux maintainer.

    As you noted: the first answer here is that you should be using Redux Toolkit. We specifically recommend against trying to write reducers and actions by hand today. We do have a "Redux Fundamentals" tutorial in our docs that shows how to hand-write Redux code, but only so that you understand the basic mechanics. For any actual app, you should be using RTK.

    The second observation is that you should not be writing TS action type unions - they don't provide any real benefit, and don't actually represent how the code runs.

    Please follow the approach shown in our Redux TS Quick Start docs page instead.