Im trying to learn typescript so i decided to do a simple shopping cart app
GitHub repository: https://github.com/CsarGomez/shopping-cart-reducers-tx
im getting the following error:
No overload matches this call. Overload 1 of 5, '(reducer: ReducerWithoutAction, initializerArg: any, initializer?: undefined): [any, DispatchWithoutAction]', gave the following error. Argument of type '(state: ShoppingInitialState, action: shoppingReducer) => { cart: (ProductInterface | undefined)[]; products: ProductInterface[]; }' is not assignable to parameter of type 'ReducerWithoutAction'. Overload 2 of 5, '(reducer: (state: ShoppingInitialState, action: shoppingReducer) => { cart: (ProductInterface | undefined)[]; products: ProductInterface[]; }, initialState: never, initializer?: undefined): [...]', gave the following error. Argument of type 'ShoppingInitialState' is not assignable to parameter of type 'never'
and i don't know what im doing wrong, it will be really appreciate if someone can explain me where the issue is, and why its happen
here's more detail:
i have a model folder that contains all the interfaces:
shopping.interface.ts
export enum ActionsTypes {
ADD_TO_CART = 'ADD_TO_CART',
REMOVE_ONE_FROM_CART = 'REMOVE_ONE_FROM_CART',
REMOVE_ALL_FROM_CART = 'REMOVE_ALL_FROM_CART',
CLEAN_CART = 'CLEAN_CART',
}
export interface shoppingReducer {
type: ActionsTypes;
payload: number;
}
export interface ShoppingInitialState {
products: Array<ProductInterface>;
cart: Array<ProductInterface>;
}
interface ProductInterface {
id: number;
image: string;
name: string;
price: number;
}
i have a folder called reducers and inside my reducer:
shopping.reducer.ts
import { ACTIONS } from '@/actions/shopping.actions';
import {
ShoppingInitialState,
shoppingReducer,
} from '@/models/shopping.interface';
export const shoppingInitialState: ShoppingInitialState = {
products: [
{
id: 1,
image: 'https://placeimg.com/200/200/tech/1',
name: 'Product 1',
price: 100,
},
{
id: 2,
image: 'https://placeimg.com/200/200/tech/2',
name: 'Product 2',
price: 200,
},
{
id: 3,
image: 'https://placeimg.com/200/200/tech/3',
name: 'Product 3',
price: 100,
},
{
id: 4,
image: 'https://placeimg.com/200/200/tech/4',
name: 'Product 4',
price: 400,
},
{
id: 5,
image: 'https://placeimg.com/200/200/tech/5',
name: 'Product 5',
price: 100,
},
{
id: 6,
image: 'https://placeimg.com/200/200/tech/6',
name: 'Product 6',
price: 600,
},
],
cart: [],
};
export function shoppingReducer(
state: ShoppingInitialState,
action: shoppingReducer
) {
const { type, payload } = action;
switch (type) {
case ACTIONS.ADD_TO_CART: {
let addCartItem = state.products.find(
(product) => product.id === payload
);
return {
...state,
cart: [...state.cart, addCartItem],
};
}
case ACTIONS.REMOVE_ONE_FROM_CART: {
}
case ACTIONS.REMOVE_ONE_FROM_CART: {
}
case ACTIONS.CLEAN_CART: {
}
default:
return state;
}
}
a folder called components with
Cart.tsx:
import { useReducer } from 'react';
import {
shoppingInitialState,
shoppingReducer,
} from '@/reducers/shopping.reducer';
const Cart: React.FC = () => {
const deleteFromCart = () => {};
const clearCart = (id: number) => {
console.log(id);
};
const [state, dispatch] = useReducer(shoppingReducer, shoppingInitialState);
const { cart } = state;
return (
<div className='cart'>
<button className='btn-primary'>Clean Cart</button>
{cart.length === 0 ? (
<div className='center'>No products yet</div>
) : (
cart.map((item) => (
<div key={item.id} className='cart__card'>
<div className='cart__details'>
<p>{item.name}</p>
<p>USD$ {item.price}</p>
</div>
<button>Remove from Cart</button>
</div>
))
)}
</div>
);
};
export default Cart;
Products.tsx:
import { useReducer } from 'react';
import {
shoppingInitialState,
shoppingReducer,
} from '@/reducers/shopping.reducer';
import { ActionsTypes } from '@/models/shopping.interface';
const Products: React.FC = () => {
const addToCart = (id: number) => {
dispatch({ type: ActionsTypes.ADD_TO_CART, payload: id });
console.log(id);
};
const deleteFromCart = () => {};
const clearCart = () => {};
const [state, dispatch] = useReducer(shoppingReducer, shoppingInitialState);
const { products } = state;
return (
<div className='products'>
{products.map((product) => (
<div key={product.id} className='product__card'>
<img src={product.image} alt='product image' />
<div className='product__details'>
<p>{product.name}</p>
<p>USD$ {product.price}</p>
</div>
<button onClick={() => addToCart(product.id)} className='btn-primary'>
Add to Cart
</button>
</div>
))}
</div>
);
};
export default Products;
and finally the app:
import '@styles/reset.scss';
import '@styles/App.scss';
import Products from '@/components/Products';
import Cart from '@/components/Cart';
function App() {
return (
<main>
<section>
<h2>Shopping Cart</h2>
<hr />
<Products />
</section>
<section className='order'>
<h2>Order Summary</h2>
<hr />
<Cart />
</section>
</main>
);
}
export default App;
im getting multiple errors a soon as i try to add an item into cart state using the reducers, more explicit when i add this line in shopping.reducers.ts
case ACTIONS.ADD_TO_CART: {
let addCartItem = state.products.find(
(product) => product.id === payload
);
return {
...state,
***cart: [...state.cart, addCartItem],***
};
CodePudding user response:
Try changing this in shopping.reducer.ts
:
export function shoppingReducer(
state = ShoppingInitialState, // Here you need to assign a value, so = instead of :
action: shoppingReducer
) {
const { type, payload } = action;
switch (type) {
case ACTIONS.ADD_TO_CART: {
let addCartItem = state.products.find(
(product) => product.id === payload
);
return {
...state,
cart: [...state.cart, addCartItem],
};
}
case ACTIONS.REMOVE_ONE_FROM_CART: {
}
case ACTIONS.REMOVE_ONE_FROM_CART: {
}
case ACTIONS.CLEAN_CART: {
}
default:
return state;
}
}
CodePudding user response:
the return type of your "shoppingReducer" dont have the same type that initialState.
///shopping.interface.ts
// types of actions in the reducer
export enum ActionsTypes {
ADD_TO_CART = 'ADD_TO_CART',
REMOVE_ONE_FROM_CART = 'REMOVE_ONE_FROM_CART',
REMOVE_ALL_FROM_CART = 'REMOVE_ALL_FROM_CART',
CLEAN_CART = 'CLEAN_CART',
}
export type CartActionType = {
type: ActionsTypes,
payload: number
}
export type IshoppingReducer = {
type: ActionsTypes;
payload: number;
}
export type State = {
cart:Array<any>
products: Array<any>;
}
export interface shoppingReducer {
type: ActionsTypes;
payload: number;
}
export interface ShoppingInitialState {
products: Array<ProductInterface>;
cart: Array<ProductInterface>;
}
interface ProductInterface {
id: number;
image: string;
name: string;
price: number;
}
/// shopping.reducer.ts
import {
CartActionType,
ShoppingInitialState,
shoppingReducer,
State,
} from '@/models/shopping.interface';
export const shoppingInitialState: ShoppingInitialState = {
products: [{
id: 1,
image: 'https://placeimg.com/200/200/tech/1',
name: 'Product 1',
price: 100,
},]
cart: [],
};
export function shoppingReducer(
state: ShoppingInitialState,
action: CartActionType
):State {
const { type, payload } = action;
switch (type) {
case ACTIONS.ADD_TO_CART: {
let addCartItem = state.products.find(
(product) => product.id === payload
);
return {
...state,
cart: [...state.cart, addCartItem],
};
}
case ACTIONS.REMOVE_ONE_FROM_CART: {
}
case ACTIONS.REMOVE_ONE_FROM_CART: {
}
case ACTIONS.CLEAN_CART: {
}
default:
return state;
}
}
//Products.tsx
import { useReducer } from 'react';
import {
shoppingInitialState,
shoppingReducer,
} from '@/reducers/shopping.reducer';
import { ActionsTypes } from '@/models/shopping.interface';
const Products: React.FC = () => {
const [state, cartDispatch] = useReducer(shoppingReducer,shoppingInitialState);
const addToCart = async(id: number) => {
cartDispatch({ type: ActionsTypes.ADD_TO_CART, payload: id });
console.log(id);
};
const deleteFromCart = () => {};
const clearCart = () => {};
const { products } = state;
return (
<div className='products'>
{products.map((product:any) => (
<div key={product.id} className='product__card'>
<img src={product.image} alt='product image' />
<div className='product__details'>
<p>{product.name}</p>
<p>USD$ {product.price}</p>
</div>
<button onClick={() => addToCart(product.id)} className='btn-primary'>
Add to Cart
</button>
</div>
))}
</div>
);
};
export default Products;