您建议如何合并具有相同属性但不同值类型的接口
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
中)。如果不清楚,请保留它 — 就我个人而言,我很乐意接受您所拥有的定义明确的代码。
我在 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
中)。如果不清楚,请保留它 — 就我个人而言,我很乐意接受您所拥有的定义明确的代码。