Skip to content

Instantly share code, notes, and snippets.

@itsMapleLeaf
Created July 17, 2021 20:43
Show Gist options
  • Save itsMapleLeaf/5422d92b333038b0a584da2bf9201b1f to your computer and use it in GitHub Desktop.
Save itsMapleLeaf/5422d92b333038b0a584da2bf9201b1f to your computer and use it in GitHub Desktop.
create a typesafe reducer with a map of immer action functions
import { Draft, produce } from "immer"
type ValueOf<T> = T[keyof T]
type ActionType<
ActionMap extends Record<string, (state: any, arg: any) => void>
> = ValueOf<
{
[K in keyof ActionMap]: ActionMap[K] extends (
state: any,
arg: infer Payload
) => void
? unknown extends Payload
? { type: K }
: { type: K; payload: Payload }
: never
}
>
function createReducer<State>() {
return function configureActions<
ActionMap extends Record<string, (state: Draft<State>, arg: any) => void>
>(actionMap: ActionMap) {
return function reducer(state: State, action: ActionType<ActionMap>) {
const handler = actionMap[action.type]
return handler ? produce(state, (draft) => handler(draft, action)) : state
}
}
}
const reducer = createReducer<{ readonly count: number }>()({
increment(state, amount: number) {
state.count += 1
},
decrement(state) {
state.count -= 1
},
reset(state) {
state.count = 0
},
})
reducer({ count: 0 }, { type: "increment", payload: 1 })
reducer({ count: 0 }, { type: "reset" })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment