mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
54 lines
1.3 KiB
TypeScript
54 lines
1.3 KiB
TypeScript
import type {Reducer, ReducerAction} from 'react';
|
|
import {useReducer} from 'react';
|
|
|
|
type ReducersObject<S = any, A = any> = {
|
|
[K in keyof S]: Reducer<S, A>;
|
|
};
|
|
|
|
type ReducersState<M> = M extends ReducersObject
|
|
? {
|
|
[P in keyof M]: M[P] extends Reducer<infer S, any> ? S : never;
|
|
}
|
|
: never;
|
|
|
|
type ReducerFromReducersObject<M> = M extends {
|
|
[P in keyof M]: infer R;
|
|
}
|
|
? R extends Reducer<any, any>
|
|
? R
|
|
: never
|
|
: never;
|
|
|
|
type AllReducerAction<M> = M extends ReducersObject
|
|
? ReducerAction<ReducerFromReducersObject<M>>
|
|
: never;
|
|
|
|
type CombinedState<S> = {} & S;
|
|
export type CombinedReducer<M extends ReducersObject> = Reducer<
|
|
CombinedState<ReducersState<M>>,
|
|
AllReducerAction<M>
|
|
>;
|
|
|
|
export function makeCombinedReducers<M extends ReducersObject>(
|
|
reducers: M
|
|
): CombinedReducer<M> {
|
|
const keys: (keyof M)[] = Object.keys(reducers);
|
|
|
|
return (state, action) => {
|
|
const nextState = {} as ReducersState<M>;
|
|
|
|
for (const key of keys) {
|
|
nextState[key] = reducers[key](state[key], action);
|
|
}
|
|
|
|
return nextState;
|
|
};
|
|
}
|
|
|
|
export function useCombinedReducer<M extends ReducersObject>(
|
|
reducers: M,
|
|
initialState: CombinedState<ReducersState<M>>
|
|
): [CombinedState<ReducersState<M>>, React.Dispatch<AllReducerAction<M>>] {
|
|
return useReducer(makeCombinedReducers(reducers), initialState);
|
|
}
|