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

Posted

技术标签:

【中文标题】您如何建议合并具有相同属性但值类型不同的接口【英文标题】:How would you suggest to merge interfaces with same properties but different value types 【发布时间】:2021-11-08 23:38:46 【问题描述】:

我在 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;
  
;

【问题讨论】:

不幸的是,我认为没有更好的方法可以做到这一点。此人有一个similar question,答案类似于您的解决方案。不过,您可以通过组合 Members 和 Error 操作来稍微缩短代码。 【参考方案1】:

您的代码在我看来很好,并且在 playground link 中表现良好。

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

在考虑这一点时,请确定您是否更有可能添加需要表达新行为的操作(例如,应将行为封装在操作中),或者添加操作的自包含函数大多数或所有新操作(这样行为应该像您一样封装在switch 中)。如果不清楚,请留下 - 就我个人而言,我很乐意接受您拥有的定义明确的代码。

【讨论】:

以上是关于您如何建议合并具有相同属性但值类型不同的接口的主要内容,如果未能解决你的问题,请参考以下文章

具有共同属性但值不同的派生类的正确设计设置

C ++如何从具有不同返回类型的接口多重继承?

如何反序列化具有相同名称但不同类型的 API 响应

如何创建具有索引签名和不同类型的固定属性的 TypeScript 接口?

具有命名属性和不同类型的任意命名索引属性的打字稿接口[重复]

如何将两个 DataTable 与内部连接连接在一起