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

联合类型+映射类型下Switch Case的TypeScript类型推断问题

TypeScript无法根据actionType推断payload类型的问题

在以下代码片段中,TypeScript编译器无法根据actionType推断参数(action.payload)的类型:

enum Actions{
ACTIONA,
ACTIONB
};

type ActionA = {
  type : Actions.ACTIONA,
  payload: {
    body: string;
    message: object;
  }
}

type ActionB = {
  type : Actions.ACTIONB,
  payload: {
    message: object;
  }
}

type ActionType = ActionA | ActionB;

const actionHandlers: {
  [key in  Actions.ACTIONA | Actions.ACTIONB]: (payload: Extract<ActionType, { type: key }>['payload']) => void
} = {
  [Actions.ACTIONA]: ({body, message}) => console.log(body, message),
  [Actions.ACTIONB]: ({message}) => console.log( message),
}

const performAction = (action: ActionType): void => {
  switch(action.type){
    case Actions.ACTIONA:
    case Actions.ACTIONB:
      return actionHandlers[action.type](action.payload); 
  }
}

错误信息:

Argument of type '{ body: string; message: object; } | { message: object; }' is not assignable to parameter of type '{ body: string; message: object; }'.
  Property 'body' is missing in type '{ message: object; }' but required in type '{ body: string; message: object; }'

一种临时解决方案是为每个case重复编写处理逻辑,但在实际代码场景中,case处理逻辑可能非常复杂,重复编写并非最优解:

case Actions.ACTIONA:
   return actionHandlers[action.type](action.payload); 
case Actions.ACTIONB:
   return actionHandlers[action.type](action.payload); 

解决方案

问题核心是合并case分支后,TypeScript无法精准关联action.type与对应payload的类型约束。以下是几种更优的解决方式:

方式1:类型断言缩小范围

在调用handler时,通过类型断言明确当前action对应的payload类型:

const performAction = (action: ActionType): void => {
  switch(action.type){
    case Actions.ACTIONA:
    case Actions.ACTIONB:
      return actionHandlers[action.type](
        action.payload as Extract<ActionType, { type: typeof action.type }>['payload']
      ); 
  }
}

方式2:重构Handler类型定义

重新定义映射类型,让每个action类型与payload的关联更清晰,配合never断言绕过编译器的推断限制(实际类型安全已由Handler类型保障):

type ActionHandlers = {
  [T in ActionType['type']]: (payload: Extract<ActionType, { type: T }>['payload']) => void
}

const actionHandlers: ActionHandlers = {
  [Actions.ACTIONA]: ({body, message}) => console.log(body, message),
  [Actions.ACTIONB]: ({message}) => console.log(message),
}

const performAction = (action: ActionType): void => {
  actionHandlers[action.type](action.payload as never);
}

方式3:使用函数重载

为performAction添加重载声明,明确每个action类型对应的参数约束,让TypeScript自动完成类型推断:

function performAction(action: ActionA): void;
function performAction(action: ActionB): void;
function performAction(action: ActionType): void {
  actionHandlers[action.type](action.payload);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 21:30:32