Home > Software design >  Typing the state of useReducer
Typing the state of useReducer

Time:12-08

I'm currently working on a Calculator on react with typescript but i'm having some issues to type the state in my reducer function. Only "any" works for now. I know that's an object with strings inside, but I don't know why it doesn't works.

Thanks for your help.

import { useReducer } from "react";
import Grid from "./components/Grid";
import NumberButton from "./components/NumberButton";
import OperatorButton from "./components/OperatorButton";

// type State = {
//   currentOperation?: string
//   result?: string
//   operator?: string
// }

export enum ACTIONS {
  ADD_NUMBER = 'add-number',
  ADD_OPERATOR = 'add-operator',
  CALCULATE = 'calculate',
  DELETE = 'delete',
  RESET = 'reset'
}

export type Action = {
  type: ACTIONS,
  payload?: { digit?: string, operator?: string }
}

const reducer = (state: any, { type, payload }: Action) => {

  console.log("State", state);

  switch (type) {
    case ACTIONS.ADD_NUMBER:
      return {
        ...state,
        currentOperation: `${state.currentOperation || ""}${payload!.digit}`
      };

   
    default:
      break;
  }
};

const App = () => {

  const [{ currentOperation, result, operator }, dispatch] = useReducer(reducer, {});

  return (
    <Grid>
      <div className="displayScreen">
        <div className="currentOperation">{currentOperation} {operator}</div>
        <div className="result">{result}</div>
      </div>
      <button onClick={() => dispatch({ type: ACTIONS.RESET })}>C</button>
    </Grid>
  )
}

export default App;

CodePudding user response:

Your switch statement is not exhaustive. In the default case you are returning nothing.

change the reducer function like this:

const reducer = (state: State, { type, payload }: Action) => {

and then:

default: 
  return state;

This should work.

Another way to type actions without Enums:

type State = {
  currentOperation?: string
  result?: string
  operator?: string
}
export type Action = 
   | { type: 'ADD_NUMBER', payload: {digit: number} }
   | { type: 'ADD_OPERATOR', payload: string};

const reducer = (state: State, action: Action) => {
  console.log("State", state);
  switch (action.type) {
    case 'ADD_NUMBER':
      return {
        ...state,
        currentOperation: `${state.currentOperation || ""}${action.payload.digit}`
      };
    case 'ADD_OPERATOR':
      return {
        ...state,
        // (payload here is a string)
      }
   
    default:
      return state;
  }
};
  • Related