DEV Community 👩‍💻👨‍💻

Kay Gosho
Kay Gosho

Posted on • Updated on

useReducer in TypeScript, strictly typed version

https://reactjs.org/docs/hooks-reference.html#usereducer

interface Action<T extends string, P = undefined> {
  type: T
  payload: P
}

type Actions = 
  | Action<'increment', { by: number }>
  | Action<'decrement', { by: number }>
  | Action<'reset', { to: number }>

type Reducer<S, A extends Action<any, any>> = (s: S, a: A) => S

const INITIAL_STATE = {
  count: 0,
} as const

const reducer: Reducer<typeof INITIAL_STATE, Actions>(state, action) => {
  switch (action.type) {
    case 'increment':
      return { count: state.count + action.payload.by };
    case 'decrement':
      return { count: state.count - action.payload.by };
    case 'reset':
      return { count: action.payload.to };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'decrement', payload: { by: 1 })}>-</button>
      <button onClick={() => dispatch({ type: 'increment', payload: { by: 1 }})}>+</button>
      <button onClick={() => dispatch({ type: 'reset', payload: { to: 0 } })}>+</button>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
waju profile image
Abolarin Olanrewaju Olabode

This is really cool.

Collapse
 
acro5piano profile image
Kay Gosho

Thanks!

Collapse
 
mconnor profile image
mike connor

missing '=' before '(state, action) =>' ??

Collapse
 
acro5piano profile image
Kay Gosho

Thanks! I've fixed!

Build Anything...


Use any Linode offering to create something for the DEV x Linode Hackathon 2022. A variety of prizes are up for grabs, inculding $1,000 USD. 👀

Join the Hackathon <-