You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript+useReducer购物车报错:参数类型不匹配求助

TypeScript useReducer购物车报错问题排查与解决

我正在学习TypeScript,开发了一个简易购物车应用,使用useReducer时遇到如下错误:

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'

在shopping.reducer.ts中执行添加商品到购物车的代码(cart: [...state.cart, addCartItem])时,错误表现更明显,以下是问题分析及解决方法:


相关代码细节

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;
}

shopping.reducer.ts(Reducer实现)

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;
  }
}

组件说明

  • Cart.tsx:通过useReducer获取购物车状态并渲染
  • Products.tsx:展示商品列表,触发添加到购物车的dispatch操作
  • App.tsx:整合Products和Cart组件

问题原因

  1. 命名冲突:接口shoppingReducer与函数shoppingReducer同名,TypeScript无法正确推断类型,导致useReducer无法识别合法的Reducer类型。
  2. 类型不兼容:state.products.find()可能返回undefined(当找不到对应ID的商品时),但cart的类型是Array<ProductInterface>,不能包含undefined,导致返回的state类型不符合定义。
  3. 代码逻辑缺陷:REMOVE_ONE_FROM_CART分支重复定义,且部分分支无返回值,干扰TypeScript的类型推断。

解决步骤

1. 修正命名冲突

将接口shoppingReducer重命名为ShoppingAction,避免与函数名冲突:

// shopping.interface.ts
export interface ShoppingAction {
  type: ActionsTypes;
  payload: number;
}

更新reducer中的类型引用:

// shopping.reducer.ts
import {
  ShoppingInitialState,
  ShoppingAction, // 替换原shoppingReducer接口
} from '@/models/shopping.interface';

export function shoppingReducer(
  state: ShoppingInitialState,
  action: ShoppingAction // 更新参数类型
) {
  // ... 原有逻辑
}

2. 处理find返回undefined的情况

确保添加到购物车的商品一定存在,过滤无效添加:

case ACTIONS.ADD_TO_CART: {
  const addCartItem = state.products.find(
    (product) => product.id === payload
  );
  // 商品不存在则直接返回原状态
  if (!addCartItem) return state;
  return {
    ...state,
    cart: [...state.cart, addCartItem],
  };
}

3. 修复重复分支与补充逻辑

删除重复的REMOVE_ONE_FROM_CART分支,并补充各分支的完整逻辑:

switch (type) {
  case ACTIONS.ADD_TO_CART: {
    // ... 上述处理逻辑
  }
  case ACTIONS.REMOVE_ONE_FROM_CART: {
    return {
      ...state,
      cart: state.cart.filter(item => item.id !== payload)
    };
  }
  case ACTIONS.REMOVE_ALL_FROM_CART: {
    return {
      ...state,
      cart: state.cart.filter(item => item.id !== payload)
    };
  }
  case ACTIONS.CLEAN_CART: {
    return {
      ...state,
      cart: []
    };
  }
  default:
    return state;
}

4. 明确useReducer的类型

在组件中使用useReducer时,显式指定状态与action类型:

import { useReducer } from 'react';
import { shoppingReducer, shoppingInitialState } from '@/reducers/shopping.reducer';
import { ShoppingInitialState, ShoppingAction } from '@/models/shopping.interface';

const [state, dispatch] = useReducer<(state: ShoppingInitialState, action: ShoppingAction) => ShoppingInitialState>(
  shoppingReducer,
  shoppingInitialState
);

内容的提问来源于stack exchange,提问作者Cesar Gomez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 02:06:53