import { useMemo, useReducer, Reducer } from 'react'; type Action = { type: string; payload?: any; }; type CreateMethods = ( state: T ) => { [P in keyof M]: (payload?: any) => T; }; type WrappedMethods = { [P in keyof M]: (...payload: any) => void; }; const useMethods = (createMethods: CreateMethods, initialState: T): [T, WrappedMethods] => { const reducer = useMemo>( () => (reducerState: T, action: Action) => { return createMethods(reducerState)[action.type](...action.payload); }, [createMethods] ); const [state, dispatch] = useReducer>(reducer, initialState); const wrappedMethods: WrappedMethods = useMemo(() => { const actionTypes = Object.keys(createMethods(initialState)); return actionTypes.reduce((acc, type) => { acc[type] = (...payload) => dispatch({ type, payload }); return acc; }, {} as WrappedMethods); }, [createMethods, initialState]); return [state, wrappedMethods]; }; export default useMethods;