React+TypeScript中如何将action作为变量传递给dispatch?
在使用React useReducer和TypeScript时,想把Action的type作为参数传递给dispatch,但遇到了类型不匹配的错误。现有Action类型定义如下:
type Actions = | {type: 'addToBag', bagProducts: string[]} | {type: "increaseQty", prodName: string} | {type: "decreaseQty", prodName: string}
尝试直接传递type参数时,无论是用普通字符串还是联合类型,都会触发TypeScript错误——核心问题是不同type对应的payload结构不一致,TypeScript无法自动匹配正确的payload类型。
方案1:限制处理特定类型的Action
如果你的函数只需要处理increaseQty和decreaseQty这类需要prodName的Action,可以直接将action参数的类型限定为这两个值,TypeScript会明确匹配对应的payload结构:
const adjustProductQty = (name: string, action: "increaseQty" | "decreaseQty") => { dispatch({ type: action, prodName: name }); };
调用示例:
adjustProductQty('apple', 'increaseQty'); adjustProductQty('apple', 'decreaseQty');
方案2:泛型函数处理所有Action类型
如果需要兼容所有Action类型,可以用泛型约束来确保传入的type和payload严格匹配:
首先提取Action的type类型:
type ActionType = Actions['type'];
然后写一个泛型函数接收完整的Action对象:
const dispatchAction = <T extends ActionType>( action: Extract<Actions, { type: T }> ) => { dispatch(action); };
调用示例:
// 自动匹配addToBag的payload结构 dispatchAction({ type: 'addToBag', bagProducts: ['apple', 'banana'] }); // 自动匹配decreaseQty的payload结构 dispatchAction({ type: 'decreaseQty', prodName: 'apple' });
方案3:拆分Type和Payload的泛型函数
如果坚持要分开传递type和payload,可以通过泛型推导来约束payload的结构:
// 提取对应type的payload类型(剔除type字段) type ActionPayload<T extends ActionType> = Omit<Extract<Actions, { type: T }>, 'type'>; const dispatchByType = <T extends ActionType>(type: T, payload: ActionPayload<T>) => { dispatch({ type, ...payload } as Actions); };
调用示例:
// TypeScript自动提示需传入prodName参数 dispatchByType('decreaseQty', { prodName: 'apple' }); // TypeScript自动提示需传入bagProducts参数 dispatchByType('addToBag', { bagProducts: ['apple'] });
错误原因说明
之前的写法报错,是因为当action参数是"addToBag" | "increaseQty" | "decreaseQty"的联合类型时,TypeScript无法确定当前type对应的payload应该是bagProducts还是prodName。比如如果传入action: 'addToBag',但你传递的是prodName,这就违反了Actions类型的定义,因此TypeScript会阻止这种潜在的错误。
内容的提问来源于stack exchange,提问作者Berg_Durden

