Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Typescript 扩展活接头类型_Typescript - Fatal编程技术网

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”}
它们将不再兼容作业。感谢您提供的详细答案,这似乎有效,我将尝试一下。特别感谢您对加宽与延伸的解释。我也尝试了另一种方法,稍后会在一个新问题中提出一些问题。