I'm a noob typescript developer, I'm working on a projct where I will have a context API that will manage my state.
I've tried many scenarios to resolve the reducer problem but I couldn't, any help is appreciated.
import React, { useReducer } from "react";
type ActionType = { type: string; payload: any };
type StateType = { [key: string]: any };
type Dispatch = (action: ActionType) => void;
type ActionFunc = (dispatch: Dispatch) => Promise<void>;
type Actions<A extends { [key: string]: ActionFunc }> = {
[key in keyof A]: ReturnType<A[keyof A]>;
};
type Reducer<S extends StateType, A extends ActionType> = (
state: S,
action: A
) => {
[key in keyof S]: any;
};
type InitializeContext<State, Action extends ActionType> = (
reducer: Reducer<State, Action>,
actions: { [key: string]: ActionFunc },
initialState: { [key in keyof State]: keyof State[key] }
) => void;
//---
//Test
//---
type TestAction = {
type: "@ADD_PRODUCT";
payload: {
id: number;
name: string;
isCat: boolean;
};
};
type TestState = { products: Array<TestAction["payload"]> };
const initialState: TestState = {
products: []
};
const reducer: Reducer<TestState, TestAction> = (state, action) => {
switch (action.type) {
case "@ADD_PRODUCT":
return {
products: [...state.products, action.payload]
};
default:
return state;
}
};
const addProduct = (dispatch: Dispatch) => async () => {};
//------
//EndTest
//------
const initializeContext: InitializeContext<StateType, ActionType> = (
reducer,
actions,
initialState
) => {
const ContextApi = React.createContext({});
const Provider: React.FC = (props) => {
const [state, dispatch] = useReducer(reducer, initialState);
const boundActions: Actions<typeof actions> = {};
for (const key in actions) {
if (Object.prototype.isPrototypeOf.call(actions, key)) {
boundActions[key] = actions[key](dispatch);
}
}
return (
<ContextApi.Provider value={{ state, ...boundActions }}>
{props.children}
</ContextApi.Provider>
);
};
// return { ContextApi, Provider }
};
initializeContext(reducer, { addProduct }, initialState); // why Type 'StateType' is not assignable to type 'TestState'
Codebox: https://codesandbox.io/s/typescript-playground-export-forked-u8ehp?file=/index.tsx:1922-1981
On L21, you set the type of reducer
to Reducer<State, Action>
. The actual reducer you assigned it is of a different type. While it might seem helpful to try to narrow the specificity on what will be passed to the Reducer, in practice this would be unenforceable: Redux will run every reducer for every action.
You can import { AnyAction } from 'redux';
and use this for the action type, and let the value of state
be set via inference.