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

如何在TypeScript中利用泛型正确获取Dva Dispatch的函数参数?

问题分析与解决方案

你的代码出现payload类型被合并为number & {test:'456'}的问题,核心原因有两个:

  1. ReplaceStr类型实现错误,未能正确提取action type中的方法名;
  2. 未对联合类型的ActionType做分布式处理,导致TypeScript将不同方法的payload类型交叉合并。

以下是修复后的完整代码:

interface RouterAction {
  type: 'router-action';
}

type DispatchRouterAction = (action: RouterAction) => any;

interface InterfaceEffects {
  firstMethod(data: { payload: { test: '456' } }): any;
  secondMethod(data: { payload: number }): any;
}

// 从action type中提取斜杠后的方法名
type ExtractMethodName<ActionType extends string> = 
  ActionType extends `${string}/${infer MethodName}` ? MethodName : never;

type ActionTypeList = 'myNamespace/firstMethod' | 'myNamespace/secondMethod';

// 为每个action type生成对应的正确Action类型
type DvaAction = {
  [T in ActionTypeList]: {
    type: T;
    payload: Parameters<InterfaceEffects[ExtractMethodName<T>]>[0]['payload'];
  }
}[ActionTypeList];

// 最终的dispatch类型,支持RouterAction和正确的DvaAction
type DispatchCustom = (action: RouterAction | DvaAction) => any;

const dispatchA = (dispatch: DispatchCustom) => {
  // 正确:payload类型为number
  dispatch({ type: 'myNamespace/secondMethod', payload: 123 });
  // 正确:payload类型为{ test: '456' }
  dispatch({ type: 'myNamespace/firstMethod', payload: { test: '456' } });
  // 正确:router-action类型
  dispatch({ type: 'router-action' });
  
  // 错误示例:payload类型不匹配,会被TypeScript提示
  // dispatch({ type: 'myNamespace/secondMethod', payload: { test: '456' } });
};

关键修复点说明

  1. 替换错误的ReplaceStr为ExtractMethodName
    专门针对命名空间/方法名的格式提取方法名,逻辑更精准,避免了原递归逻辑的错误。

  2. 用映射类型生成正确的联合Action类型
    通过{ [T in ActionTypeList]: ... }遍历所有action type成员,为每个成员生成独立的Action类型,确保每个type对应唯一的payload类型,最终得到联合类型的DvaAction。

  3. 重构DispatchCustom类型
    直接让dispatch接受RouterAction或DvaAction,TypeScript会根据传入的type自动推断payload的正确类型,不会再出现交叉合并的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 11:25:43