gpt4 book ai didi

typescript - 在不同的模块中扩大 TypeScript 中的标记/区分联合?

转载 作者:搜寻专家 更新时间:2023-10-30 21:13:50 24 4
gpt4 key购买 nike

我有一个系统用于通过套接字连接来回传递 JSON 消息。它使用标记联合作为消息类型:

export type ErrorMessage = { kind: 'error', errorMessage: ErrorData };
export type UserJoined = { kind: 'user-joined', user: UserData };
// etc
export type Message = ErrorMessage | UserJoined | /*etc*/;

它在基本代码中运行得相当好,但我有一个构建在它之上的模块,我想扩展代码。我有一个新的消息类型要添加:

export type UserAction = { kind: 'user-action', action: Action }

这里的问题是我无法扩展“消息”以将我的新 UserAction 包含到联合中。我想我可以制作自己的扩展消息:

export type ExtendedMessage = Message | UserAction;

但这里的问题是这看起来很笨重,第一。我无法将我的新 UserAction 传递到任何需要消息的方法中,即使代码实际上应该可以正常工作。以后想要同时扩展我的模块和基本模块的任何其他人都需要创建第三种类型:export type ExtendedMessageAgain = ExtendedMessage | MyNewMessage.

所以。我已经看到通过添加新的 .d.ts 文件扩展了其他属性的接口(interface)(比如 passport 如何扩展 Express JS 的 Request 对象以添加身份验证属性),我认为标记联合也必须存在类似的东西,对吧?

但似乎并非如此。我到处搜索,没有看到任何地方使用这种模式。这让我相信,也许我的设计在某种程度上是错误的。但我没有办法解决它。

我不想使用类,因为类型信息通过网络被删除; kind 属性必须存在。我喜欢这种范式:

declare var sendMessage = (message: Message) => void;
sendMessage( { kind: 'error', errorMessage: { /* */ } }); // ok
sendMessage( { kind: 'random', parameter: { /* */ } }); // error, no kind 'random'
sendMessage( { kind: 'error', message: { /* */ } }); // error, no property 'message' on 'error'

但我看到的唯一解决方案是使 Message 成为接口(interface)基础,如下所示:

export interface Message { kind: string }
export interface ErrorMessage extends Message { errorMessage: ErrorData }

declare var sendMessage = (message: Message) => void;

sendMessage( { kind: 'error', errorMessage: { /* */ } }); // ok
sendMessage( { kind: 'random', parameter: { /* */ } }); // ok
sendMessage( { kind: 'error', message: { /* */ } }); // ok

而且这个方法失去了上面所有的类型保护。

那么...有没有办法在多个模块中扩展 Tagged Union,影响类型的原始名称,而不定义新类型?还是这里有我只是没有看到的更好的设计?

这是启发这篇文章的代码:https://github.com/RonPenton/NotaMUD/blob/master/src/server/messages/index.ts

我正在寻求大规模重构,以便我可以将所有消息移出到单独的模块中,而不是随着时间的推移这个文件变得一团糟。

最佳答案

您可以这样做来定义 Message 的联合类型:

export interface MessageTypes {}
export type Message = MessageTypes[keyof MessageTypes]

然后无论您在哪里定义新的消息类型,都执行以下操作:

export type UserAction = { kind: 'user-action', action: Action }

declare module '../message' { // Where you define MessageTypes
interface MessageTypes {
UserAction: UserAction
}
}

因此 MessageTypes 接口(interface)的值成为联合类型,您可以使用声明合并向接口(interface)添加更多值,这将自动更新联合类型。

您可以查看 TS 文档以获取有关声明合并的更多信息:https://www.typescriptlang.org/docs/handbook/declaration-merging.html

关于typescript - 在不同的模块中扩大 TypeScript 中的标记/区分联合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46392758/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com