Typescript 扩展活接头类型
假设我有以下类型脚本类型定义:Typescript 扩展活接头类型,typescript,Typescript,假设我有以下类型脚本类型定义: export type Command = { AggregateId: string} export type AddUser = (command: Command) => Promise<{streamId: string}> export type RemoveUser = (command: Command) => Promise<{streamId: string}> type CommandHandler =
export type Command = { AggregateId: string}
export type AddUser = (command: Command) => Promise<{streamId: string}>
export type RemoveUser = (command: Command) => Promise<{streamId: string}>
type CommandHandler =
| AddUser
| RemoveUser
export-type命令={AggregateId:string}
导出类型AddUser=(命令:command)=>Promise
导出类型RemoveUser=(命令:command)=>Promise
类型CommandHandler=
|地址用户
|移除用户
有没有办法在库中定义
CommandHandler
,而不使用AddUser
和removeeuser
而使用“attach”呢在一个引用了包含CommandHandler
的库的项目中,CommandHandler
?我相当确定,在这样做之后,您不能更改CommandHandler
的含义
您可以将CommandHandler
定义为:
export type CommandHandler = (command: Command) => Promise<{streamId: string}>
首先是一些术语。。。打字机脚本中的某些术语对之间存在着二元性,而且常常混淆。“扩展”一词通常指的是缩小类型以使其更受约束。在您的情况下,当您说要“扩展”联合时,您的意思与
extends
的意思不同。相反,您希望加宽类型以使其受约束更少。在TypeScript中没有类似的术语。。。在Java之类的语言中,您可以称之为super
。无论如何,要明确的是,您希望在库中有一个空的联合,并允许其他模块向其中添加成分,从而扩大(而不是扩展)它
有一个名为的语言特性,它允许您通过“重新打开”模块/名称空间/接口并向其添加属性/方法来扩充现有类型。乍一看似乎没有帮助,因为您要更改的类型是类型别名(即,type X=…
),您无法重新打开这些别名。而且无论如何,您都不想向它添加任何属性/方法
这里的技巧是创建一个像CommandHandlerMap
这样的接口,其属性键是伪值,其属性值是您要查找的CommandHandler
联合的元素。然后您可以定义类型CommandHandler=CommandHandlerMap[keyof CommandHandlerMap]
。通过合并到模块中的CommandHandlerMap
,您将自动使CommandHandler
联合获得一个组件
代码可能如下所示:
library.ts
export type Command = { AggregateId: string };
export type CommandHandlerResult = { streamId: string };
export interface CommandHandlerMap {
// will merge into this interface
}
export type CommandHandler = CommandHandlerMap[keyof CommandHandlerMap]
import * as Library from './library';
export interface AddUserCommand extends Library.Command {
username: string;
somethingElse: number;
}
export type AddUser =
(command: AddUserCommand) => Promise<Library.CommandHandlerResult>;
// reopen the CommandHandlerMap interface in the library module
declare module './library' {
export interface CommandHandlerMap {
AddUser: AddUser // add this
}
}
import * as Library from './library';
export interface RemoveUserCommand extends Library.Command {
username: string;
withExtremePrejudice: boolean;
}
export type RemoveUser =
(command: RemoveUserCommand) => Promise<Library.CommandHandlerResult>;
// reopen the CommandHandlerMap interface in the library module
declare module './library' {
export interface CommandHandlerMap {
RemoveUser: RemoveUser // add this
}
}
import * as Library from './library';
import { RemoveUser, RemoveUserCommand } from './removeUser';
const handler: Library.CommandHandler = async (c: RemoveUserCommand) => {
return {
streamId: c.username
}
}; // okay
// const handler: AddUser | RemoveUser
addUser.ts
export type Command = { AggregateId: string };
export type CommandHandlerResult = { streamId: string };
export interface CommandHandlerMap {
// will merge into this interface
}
export type CommandHandler = CommandHandlerMap[keyof CommandHandlerMap]
import * as Library from './library';
export interface AddUserCommand extends Library.Command {
username: string;
somethingElse: number;
}
export type AddUser =
(command: AddUserCommand) => Promise<Library.CommandHandlerResult>;
// reopen the CommandHandlerMap interface in the library module
declare module './library' {
export interface CommandHandlerMap {
AddUser: AddUser // add this
}
}
import * as Library from './library';
export interface RemoveUserCommand extends Library.Command {
username: string;
withExtremePrejudice: boolean;
}
export type RemoveUser =
(command: RemoveUserCommand) => Promise<Library.CommandHandlerResult>;
// reopen the CommandHandlerMap interface in the library module
declare module './library' {
export interface CommandHandlerMap {
RemoveUser: RemoveUser // add this
}
}
import * as Library from './library';
import { RemoveUser, RemoveUserCommand } from './removeUser';
const handler: Library.CommandHandler = async (c: RemoveUserCommand) => {
return {
streamId: c.username
}
}; // okay
// const handler: AddUser | RemoveUser
这就行了。您可以看到Library.CommandHandler
被理解为AddUser | RemoveUser
。请注意,CommandHandlerMap
键恰好是的“AddUser”
和的“RemoveUser”
,但这不是必需的。我们可以用键“BlahBlah”
或“!!!@#$”
合并到CommandHandlerMap
。它们是虚拟关键点,只需唯一(因为您不想与现有关键点冲突)即可工作
此方法的主要警告可能是,您在模块中引入的任何错误最终都可能被标记在库代码中,而不是您的模块中。例如,如果库中的代码假定CommandHandler
肯定是函数类型,并且模块中有人将非函数值合并到union中,则库中可能会显示错误。这有点难以调试
无论如何,希望这能给你一些想法。祝你好运
您这样做的用例是什么?既然
AddUser
和removeeuser
实际上是同一类型的用户,那么您打算如何处理该联合类型?请参阅我对您答案的评论。我将相应地更新我的原始问题。您可以使用声明合并来完成此操作。。。如果在我到达一台真正的机器时没有其他人发布解决方案,那么我会这样做。是否可能将一个AddUserCommand
(源自Command
)传递给AddUser
,而RemoveUser
不会接受它?@AlexanderZeitler-恐怕我不知道。如果AddUserCommand
和RemoveUserCommand
不添加任何功能,它们最终会相互分配。也就是说,我的第一个想法(下一个评论)不起作用,因为它们与作业兼容。当然,如果您将属性添加到AddUserCommand
中,并将不同的属性添加到RemoveUserCommand
中,这会起作用。但是如果您有接口AddUserCommand扩展命令{type:“add”}
和接口RemoveUserCommand扩展命令{type:“remove”}
它们将不再兼容作业。感谢您提供的详细答案,这似乎有效,我将尝试一下。特别感谢您对加宽与延伸的解释。我也尝试了另一种方法,稍后会在一个新问题中提出一些问题。