Reducer Typescript Error: No overload matches this call

When the reducer return Union Type, the following error occurred.

enter image description here

It's okay if I return state, but why do I get error??

interface InputStates {
  value: string;
  isTouched: boolean;
}
interface Action {
  type: string;
}

const initialState = {
  value: '',
  isTouched: false
}

function inputReducer(state:InputStates, action:Action):InputStates|Error{
  switch(action.type) {
    case 'CHANGE_INPUT':
      return {
        value: state.value,
        isTouched: true
      }
    default:
      return new Error('Unhandled Action')
  }
}

function useInput() {
  const [state, dispatch] = useReducer(inputReducer, initialState);
}

Solution 1:

Because you return ImputStates | Error from the reducer, that is the actual type of your state. You'll need to adjust your reducer to acknowledge this. Here's one example of how to address it:

TS Playground

function inputReducer (state: InputStates | Error, action: Action): InputStates | Error {
  if (state instanceof Error) return state;

  switch (action.type) {
    case 'CHANGE_INPUT':
      return {
        value: state.value,
        isTouched: true,
      };
    default:
      return new Error('Unhandled Action');
  }
}

Alternatively, you can move the potential error onto a property of the state instead:

TS Playground

interface InputStates {
  error?: Error;
  value: string;
  isTouched: boolean;
}

// ...

function inputReducer (state: InputStates, action: Action): InputStates {
  switch (action.type) {
    case 'CHANGE_INPUT':
      return {
        value: state.value,
        isTouched: true,
      };
    default:
      return {...state, error: new Error('Unhandled Action')};
  }
}

which is probably a more common approach and easier to work with in your components which subscribe to the state.