Created
November 14, 2023 17:05
-
-
Save AntanasGa/1820078b0bf274379890a5cbecb151b8 to your computer and use it in GitHub Desktop.
react reducer map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useReducer } from "react"; | |
type ReducerInvokerMap<S, T> = { | |
[K in keyof T]:T[K] extends (this: S) => S | |
? () => void | |
: T[K] extends (this: S, arg: infer Arg) => S | |
? Arg extends object | |
? (arg: Arg) => void | |
: never | |
: never | |
} | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
type Actor<S> = ((this: S) => S) | ((this: S, argument: any) => S) | |
export type ActorMap<S> = Record<string, Actor<S>>; | |
const hasNoParameter = <P, R>(fn: ((argument: P) => R) | (() => R)): fn is (() => R) => { | |
return !fn.length; | |
} | |
export default function useReducerMap<S extends object, R extends Record<string, Actor<S>>>(state: S, reducers: R): [S, ReducerInvokerMap<S, typeof reducers>] { | |
type Action = { | |
[K in keyof R]: R[K] extends (this: S, arg: infer Arg) => S | |
? Arg | |
: never | |
}[keyof R] | |
& { type: keyof R }; | |
const reducerInstance = (instanceState: S, action: Action): S => { | |
const { type, ...initiator } = action; | |
const handler = reducers[type]; | |
if (typeof handler !== "function") { | |
return instanceState; | |
} | |
return hasNoParameter(handler) ? handler.apply(state) : handler.apply(state, [initiator]); | |
}; | |
const [reducerState, reducer] = useReducer(reducerInstance, state); | |
const namedReducers = {} as ReducerInvokerMap<S, typeof reducers>; | |
for (const k in reducers) { | |
type Item = (typeof namedReducers)[keyof R]; | |
type ActParams = Item extends ((args: infer Arg) => S) ? Arg : never; | |
// assertion bad, but a nececery evil here | |
namedReducers[k] = ((act?: ActParams) => reducer({type: k, ...(act ?? {})} as Action)) as Item; | |
} | |
return [reducerState, namedReducers] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment