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

如何在TypeScript的useReducer Hook中重载Payload类型?

问题:useReducer中Action类型定义引发TypeScript报错

我在函数组件中初始化了useReducer Hook,需要在listReducer中实现两个动作:

  • CREATE:将state的list赋值为User[]类型数组,payload应为User[]
  • DELETE:通过_id(字符串类型)删除单个元素,payload应为字符串

当前定义的Action类型如下:

type Action = {
  type: ActionKind,
  payload: User[] | string;
}

触发TypeScript报错:TS2339: Property 'list' does not exist on type 'string | User[]'

尝试将payload定义为包含list(User[])和id(string)的对象,但必填属性会引发错误;设为可选属性又会出现list: User[] | undefined和id: string | undefined的问题,请问如何正确定义Action类型解决该问题?

相关代码

type State = {
  list: User[];
}

const initialListState: State = {
  list: [],
};

enum ActionKind {
  CREATE = 'CREATE',
  DELETE = 'DELETE',
}

function listReducer(state: State, action: Action): State {
  const { type, payload } = action;
  switch (type) {
    case ActionKind.CREATE:
      return { list: action.payload };
    case ActionKind.DELETE:
      return {
        list: state.list.filter((el) => el._id !== action.payload._id),
      };
    default:
      return state;
  }
}

export const DashBoard = () => {
  const [state, dispatch] = useReducer(listReducer, initialListState);

  useEffect(() => {
    if (allUsers && allUsers.length > 0) {
      dispatch({ type: ActionKind.CREATE,
        payload: allUsers,
      });
    }
  }, [allUsers]);
export interface User {
  _id: string;
  name: string;
  age: string;
  email: string;
  password: string;
  isAdmin: boolean;
}

解决方案:用联合类型区分不同动作的Action

核心思路是为每个ActionKind定义专属的Action类型,再通过联合类型组合,让TypeScript能根据type自动推断对应payload的类型,实现类型窄化。

修改后的Action类型定义

// 为CREATE动作定义专属Action类型
type CreateAction = {
  type: ActionKind.CREATE;
  payload: User[];
};

// 为DELETE动作定义专属Action类型
type DeleteAction = {
  type: ActionKind.DELETE;
  payload: string;
};

// 组合成联合类型
type Action = CreateAction | DeleteAction;

修改后的Reducer逻辑

function listReducer(state: State, action: Action): State {
  switch (action.type) {
    case ActionKind.CREATE:
      // TypeScript自动推断payload为User[]类型
      return { list: action.payload };
    case ActionKind.DELETE:
      // TypeScript自动推断payload为string类型
      return {
        list: state.list.filter((el) => el._id !== action.payload),
      };
    default:
      return state;
  }
}

原理说明

联合类型让每个动作的type和payload形成一一对应的绑定关系,TypeScript在switch分支中会自动进行类型窄化:当匹配到ActionKind.CREATE时,会自动认定action是CreateAction类型,payload必然是User[];匹配到ActionKind.DELETE时同理,payload必然是字符串,彻底消除了联合类型的歧义问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 18:55:24