I'm trying to build a generic Store using React's useReducer and useContext but I'm having an issue with the inference of the default state.
The store generator function is the following:
export function generateStore<Actions extends ReducerAction, State = any>(defaultValue: State, reducer: (state: State, action: Actions) => State): {
provider: (props: { children: ReactNode }) => ReactElement;
dispatcher: (action: Actions) => void;
useStore: () => State;
} {
const store = createContext(defaultValue);
const { Provider } = store;
let dispatch: React.Dispatch<Actions>;
const ProviderElm = (props: { children: ReactNode }): ReactElement => {
const { children } = props;
const [state, dispatcher] = useReducer(reducer, defaultValue);
dispatch = dispatcher;
return <Provider value={state}>{children}</Provider>;
};
return {
provider: ProviderElm,
dispatcher: (action: Actions) => dispatch && dispatch(action),
useStore: () => useContext(store),
};
}
An initializer example could be:
const defaultState = {
auth: {
authenticated: false,
},
};
type StoreActions =
| {
type: 'LOGIN';
payload: {
token: string;
};
}
| {
type: 'LOGOUT';
};
const { dispatcher, provider, useStore } = generateStore<StoreActions>(
defaultState,
(state = defaultState, action) => {
switch (action.type) {
case 'LOGIN': {
const { token } = action.payload;
return {
...state,
auth: {
authenticated: true,
token,
},
};
}
case 'LOGOUT': {
return {
...state,
auth: {
authenticated: false,
token: null,
},
};
}
default:
return defaultState;
}
},
);
The issue is that the State generic of generateStore can't infer itself as the typeof the parameter defaultValue.
It always requires me to initialize it like this or else the intellisense won't work out the type:
generateStore<StoreActions, typeof defaultState>
Any idea on how I make this work and why it currently can't infer the type?