Blog>
Snippets

Refactoring Reducers for Improved Type Inference

Show a before and after comparison of a reducer function to illustrate the shift from loosely typed to strict and accurate type definitions.
// BEFORE: Loosely typed reducer function
function counterReducer(state = { count: 0 }, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
}
This is a loosely typed reducer function before refactoring. The function accepts any action without type safety, potentially leading to runtime errors if incorrect actions are dispatched.
// AFTER: Strictly typed reducer function with TypeScript
// Define action types
type IncrementAction = { type: 'INCREMENT' };
type DecrementAction = { type: 'DECREMENT' };
// Union type for all action types accepted by the reducer
type Action = IncrementAction | DecrementAction;

// Define the state type
interface State {
  count: number;
}

// Reducer function with explicit type annotations
function counterReducer(state: State = { count: 0 }, action: Action): State {
  switch (action.type) {
    case 'INCREMENT':
      return { count: state.count + 1 };
    case 'DECREMENT':
      return { count: state.count - 1 };
    default:
      return state;
  }
}
This is a refactored reducer function with TypeScript for improved type inference. The types for actions are explicitly defined, ensuring that the reducer function only accepts actions of known types and that the state conforms to the defined state structure.