具有多个有效负载选项的 Typescript 和 Reducer 函数

Typescript and Reducer function with multiple payload options

我是 typescript 的新手,我正在尝试编写一个具有三个可能有效负载值的 reducer 函数:无值、字符串或数字。我使用的是受歧视的联合类型,从我读过的内容来看,我认为我的代码应该可以工作,但事实并非如此。

type StateType = {
  isModalOpen: boolean;
  modalContent: string;
  people: {
    id: number;
    name: string;
  }[];
};

type NoPayloadAction = {
  type: string;
};

type NamePayloadAction = {
  type: string;
  payload: {
    name: string;
  };
};

type IdPayloadActionType = {
  type: string;
  payload: {
    id: number;
  };
};

type ActionType = NoPayloadAction | NamePayloadAction | IdPayloadActionType;

const ACTIONS = {
  ADD_ITEM: 'ADD_ITEM',
  NO_ACTION: 'NO_ACTION',
  CLOSE_MODAL: 'CLOSE_MODAL',
  REMOVE_ITEM: 'REMOVE_ITEM',
};

// reducer function
const reducer = (state: StateType, action: ActionType) => {
  switch (action.type) {
    case ACTIONS.ADD_ITEM:
      return {
        people: [
          ...state.people,
          { id: new Date().getTime(), name: action.payload.name },
        ],
        isModalOpen: true,
        modalContent: 'item added',
      };
    case ACTIONS.NO_ACTION:
      return { ...state, isModalOpen: true, modalContent: 'enter a value' };
    case ACTIONS.CLOSE_MODAL:
      return { ...state, isModalOpen: false, modalContent: '' };
    case ACTIONS.REMOVE_ITEM:
      const newPeople = state.people.filter(
        (person) => person.id !== action.payload.id
      );
      return {
        people: [...newPeople],
        isModalOpen: true,
        modalContent: 'item removed',
      };
    default:
      return state;
  }
};

Typescript 抛出两个错误: 下面的行会引发此错误:属性 'payload' 在类型 'ActionType' 上不存在。 属性 'payload' 在类型 'NoPayloadAction'

上不存在
{ id: new Date().getTime(), name: action.payload.name },

(person) => person.id !== action.payload.id

NoPayloadAction 类型没有有效载荷,但其他两个有,据我所知,它们匹配它们的类型,因为一个有一个 id:number 字段,另一个有一个 name:string 字段。对此我真的很纳闷。

目前,无法保证传递给您的 action 变量的内容不是 NoPayloadAction。如果你确定你的 action 变量确实有一个有效负载,你总是可以使用 as 关键字告诉打字稿你知道变量是什么。例如:

return { id: new Date().getTime(), name: (action as NamePayloadAction).payload.name },