您建议如何合并具有相同属性但不同值类型的接口

How would you suggest to merge interfaces with same properties but different value types

我在 ReactJS 上使用 useReducer,我已经定义了几个操作接口以在我的 reducer function 中使用它们。我看到我使用相同的属性,但有时使用不同的有效负载值。

interface MembersAction {
  type: "JOIN" | "LEAVE";
  payload: string;
}

interface MessagesAction {
  type: "MESSAGE";
  payload: Message;
}

interface ErrorAction {
  type: "ERROR";
  payload: string;
}

interface RoomAction {
  type: "ROOM";
  payload: RoomData;
}

老实说,感觉有点臃肿,我觉得必须有更好的方法来实现我正在做的事情。

这里是 reducer 函数:

type Action = MembersAction | MessagesAction | RoomAction | ErrorAction;

const reducer = (state: RoomState, action: Action) => {
  switch (action.type) {
    case "JOIN":
      return {
        ...state,
        members: [...state.members, action.payload],
      };
    case "LEAVE":
      return {
        ...state,
        members: state.members.splice(state.members.indexOf(action.payload), 1),
      };
    case "MESSAGE":
      return {
        ...state,
        messages: [...state.messages, action.payload],
      };
    case "ROOM":
      return action.payload;
    case "ERROR":
      return state.error
        ? {
            ...state,
          }
        : {
            ...state,
            error: action.payload,
          };
    default:
      return state;
  }
};

你的代码在我看来很好,而且似乎在 playground link 中表现良好。

  • 您已将其正确表达为 discriminated union,因此 TypeScript 在 switch 块中正确推断出您的 payload 类型。
  • 您的 payload 类型在您的不同 Action 之间不兼容,因此通过多态处理 payload 在这里没有太多收获。
  • 你的 reducer 近似于 visitor pattern,尽管 Typescript 的结构类型意味着你避免了一些通常与该模式相关的接口。如果你的 reducer 表达了一个操作本质上是一个 Action 应该能够对自己做的事情,我可以看到重构的价值,所以每个 Action 都提供一个方法的实现,就像你的reducer 可以,但是接受一些 class 定义样板而不是您的 switch 语句样板。

在思考这个问题时,决定您是否更有可能添加需要表达新行为的动作(这样的行为应该封装在一个动作中),或者添加独立的功能对大多数或所有新操作进行操作(这样的行为应该像您一样封装在 switch 中)。如果不清楚,请保留它 — 就我个人而言,我很乐意接受您所拥有的定义明确的代码。