Reputation: 471
I'm learning TypeScript and I have a difficulty to setup my reducer properly.
BasketContext.tsx
import React, { useContext, useReducer } from "react";
import BasketReducer from "../reducers/BasketReducer";
const BasketContext = React.createContext<any>(undefined);
export interface IBasketState {
products: [
{
name: string;
price: number;
quantity: number;
}
];
totalPrice: number;
}
const initialState: IBasketState = {
products: [
{
name: "",
price: 0,
quantity: 0,
},
],
totalPrice: 0,
};
export const BasketContextProvider = ({ children }: { children: ReactNode }) => {
const [basketState, dispatch] = useReducer<IBasketState>(BasketReducer, initialState);
return <BasketContext.Provider value={{ basketState }}>{children}</BasketContext.Provider>;
};
export const useBasketContext = () => {
return useContext(BasketContext);
};
BasketReducer.ts
import React from "react";
import { IBasketState } from "../contexts/BasketContext";
interface IBasketAction {
type: "Add item" | "Remove item";
payload?: string;
}
const BasketReducer = (basketState: IBasketState, action: IBasketAction) => {
if (action.type === "Add item") {
console.log("Add iteeeeeeem");
return { ...basketState };
}
};
export default BasketReducer;
When I hover my mouse over const [basketState, dispatch] = useReducer<IBasketState>(BasketReducer, initialState);
I've got an error:
Type 'IBasketState' does not satisfy the constraint 'Reducer<any, any>'. Type 'IBasketState' provides no match for the signature '(prevState: any, action: any): any'.ts(2344)
Also is it possible to initialize my initialState with empty array products? Currently I use empty string and 0.
Upvotes: 0
Views: 1052
Reputation: 120450
Your reducer function must return a state (either a new state or the unmodified, passed-in state) in all cases. In your code, you are implicitly returning undefined
if there's no match for the incoming action.
// add a return-type annotation
const BasketReducer =
(basketState: IBasketState, action: IBasketAction) : IBasketState => {
if (action.type === "Add item") {
console.log("Add iteeeeeeem");
return { ...basketState };
}
return basketState; // no match, return same state
};
You are also using incorrect generic types for your call. The generic types for this call are a little complex, but you should be able to remove the generic type annotations and just let the compiler correctly infer the right types for your reducer i.e.:useReducer<IBasketState>(...
useReducer(BasketReducer, initialState)
Upvotes: 3