use-immer
use-immer copied to clipboard
Enhance `userImmerReducer`'s type by providing function overloads
In @types/react, they provide different useReducer overloads for the type support in different usages. There are totally 5 overloads.
function useReducer<R extends ReducerWithoutAction<any>, I>(
reducer: R,
initializerArg: I,
initializer: (arg: I) => ReducerStateWithoutAction<R>,
): [ReducerStateWithoutAction<R>, DispatchWithoutAction];
function useReducer<R extends ReducerWithoutAction<any>>(
reducer: R,
initializerArg: ReducerStateWithoutAction<R>,
initializer?: undefined,
): [ReducerStateWithoutAction<R>, DispatchWithoutAction];
function useReducer<R extends Reducer<any, any>, I>(
reducer: R,
initializerArg: I & ReducerState<R>,
initializer: (arg: I & ReducerState<R>) => ReducerState<R>,
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
function useReducer<R extends Reducer<any, any>, I>(
reducer: R,
initializerArg: I,
initializer: (arg: I) => ReducerState<R>,
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
function useReducer<R extends Reducer<any, any>>(
reducer: R,
initialState: ReducerState<R>,
initializer?: undefined,
): [ReducerState<R>, Dispatch<ReducerAction<R>>];
The first two are for the reducers without actions, it seems that we will always need actions if we want to use useImmerReducer, so I think we can ignore them.
Follow the rest 3 overloads, I think we can also provide 3 similar useImmerReducer overloads, like
export type ImmerReducer<S, A> = (draftState: Draft<S>, action: A) => void | (S extends undefined ? typeof nothing : S);
export function useImmerReducer<S, A, I>(
reducer: ImmerReducer<S, A>,
initializerArg: S & I,
initializer: (arg: S & I) => S,
): [S, Dispatch<A>];
export function useImmerReducer<S, A, I>(
reducer: ImmerReducer<S, A>,
initializerArg: I,
initializer: (arg: I) => S,
): [S, Dispatch<A>];
export function useImmerReducer<S, A>(
reducer: ImmerReducer<S, A>,
initialState: S,
initializer?: undefined,
): [S, Dispatch<A>];
export function useImmerReducer<S, A, I>(
reducer: ImmerReducer<S, A>,
initializerArg: S & I,
initializer?: (arg: S & I) => S,
) {
const cachedReducer = useMemo(() => produce(reducer), [reducer]);
return useReducer(cachedReducer, initializerArg as any, initializer as any);
}
BTW: I think the name ImmerReducer could be better than Reducer since there is already a type Reducer from @types/react.