Home > OS >  useRecuder typescript error Argument of type '(type, action) => { state: (...}' is no
useRecuder typescript error Argument of type '(type, action) => { state: (...}' is no

Time:08-27

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;
  • Related