import {Reducer, ReducerAction, useReducer} from 'react'; type ReducersObject = { [K in keyof S]: Reducer; }; type ReducersState = M extends ReducersObject ? { [P in keyof M]: M[P] extends Reducer ? S : never; } : never; type ReducerFromReducersObject = M extends { [P in keyof M]: infer R; } ? R extends Reducer ? R : never : never; type AllReducerAction = M extends ReducersObject ? ReducerAction> : never; type CombinedState = {} & S; export type CombinedReducer = Reducer< CombinedState>, AllReducerAction >; export function makeCombinedReducers( reducers: M ): CombinedReducer { const keys: (keyof M)[] = Object.keys(reducers); return (state, action) => { const nextState = {} as ReducersState; for (const key of keys) { nextState[key] = reducers[key](state[key], action); } return nextState; }; } export function useCombinedReducer( reducers: M, initialState: CombinedState> ): [CombinedState>, React.Dispatch>] { return useReducer(makeCombinedReducers(reducers), initialState); }