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_Types_Typescript Generics - Fatal编程技术网

Typescript 当某些具有相同形状/属性时,从联合类型提取

Typescript 当某些具有相同形状/属性时,从联合类型提取,typescript,types,typescript-generics,Typescript,Types,Typescript Generics,我正在尝试构建一个CQRS风格的命令总线的实现,其中命令总线的接口是一个单一功能,dispatch: const result=dispatch(消息) dispatch函数的类型签名如下: 类型分派=(消息:消息)=>结果 例如,假设我们想要提供一个Git回购的接口。其中一些消息可能是: 类克隆{ 构造函数(公共只读远程URL:string){} } 班级结帐{ 构造函数(公共只读branchName:string){} } 类RevParse{ 构造函数(公共只读branchName:s

我正在尝试构建一个CQRS风格的命令总线的实现,其中命令总线的接口是一个单一功能,
dispatch

const result=dispatch(消息)
dispatch
函数的类型签名如下:

类型分派=(消息:消息)=>结果
例如,假设我们想要提供一个Git回购的接口。其中一些消息可能是:

类克隆{
构造函数(公共只读远程URL:string){}
}
班级结帐{
构造函数(公共只读branchName:string){}
}
类RevParse{
构造函数(公共只读branchName:string){}
}
对于每条
消息
,都有一种已知类型的
结果
。经过一些实验,我认为表达“协议”的正确方式如下:

type Protocol=[Clone,void]|[Checkout,void]|[RevParse,string]
协议是元组类型的联合,每个元组类型表示
消息
和预期类型的
结果
之间的关系。在这个例子中,应该只期望
RevParse
返回任何有趣的内容,其他的只返回void

为了能够为给定的
消息
计算出预期的
结果
,我必须使用
提取
实用程序类型,如下所示:

类型结果=提取[1]
类型分派=(消息:消息)=>结果
然而,我发现当两条消息具有相同的属性时,这似乎失败了。例如,我可以从
签出
消息返回
字符串
。我假设这是因为
Extract
匹配
Checkout
RevParse
,当给定
Checkout
类型以查找正确的
结果时,这两种类型看起来都像
{branchName:string}

//应该失败,类型错误,因为协议说签出应该返回void。
常量checkoutResult:Result='string'
//常量签出结果:字符串| void
关于这个问题,我还有其他问题,但首先我需要理解如何正确表达
消息
结果
类型之间的关系。我对
结果的假设是否正确?我应该做一些与使用元组并集完全不同的事情吗?我是否需要为每条消息添加一些属性来唯一标识它?还有别的吗


我真的不知道您试图构建的用例和上下文,但我觉得
分派
返回不同的类型在这里不是一个好做法(有些情况下可能需要:)。你可以用

无论如何,假设这个用例是合法的:

正如您所提到的,
Extract
在为结果指定
Checkout
时同时匹配
Checkout
RevParse
。 事实上,他说:

提取
通过从T中提取可分配给U的所有属性来构造类型

在您的情况下,
[Checkout,void]
[RevParse,string]
可分配给
[Checkout,any]
(当您生成结果时) 这意味着
签出
RevParse
可分配给
签出
无效
字符串
可分配给
任何

原因是,对于类,Typescript使用结构类型,如下所示:

它们(类)既有静态类型也有实例类型。比较两个 类类型的对象,仅比较实例的成员。 静态成员和构造函数不影响兼容性

相反地

类中的私有成员和受保护成员会影响它们的兼容性

因此,重要的是类型的结构,而不是类型的名称。如果两种类型在结构上相同,则可以互换。 如果你不想发生这种情况,你可以使用“名义打字”。有几种方法,尽管我认为它应该作为例外使用,因为目前它还不是Typescript中的原生方法。有一个电流,所以它可能很快成为本地TS,使用“唯一”关键字。目前:

  • 您可以将私有属性添加到类中以使其不同,即使它们具有不同的名称
  • 您可以使用具有不同名称的静态属性,使用“Brand”后缀,正如所建议和使用的那样
  • 这将解决您的第二个问题,它将成为:

    // const checkoutResult: void
    
    对于dispatch函数,应使用已定义的结果类型执行以下操作:

     const dispatch = <Message extends Protocol[0]>(message: Message): Result<Message> => {
        if (message instanceof Clone) {
            // do clone stuff
            return
        }
        if (message instanceof Checkout) {
            // do checkout stuff
    
            // should insist that I return void here
            return 'should not be allowed'
        }
        if (message instanceof RevParse) {
            const { branchName } = message
            // do revparse stuff
            return 'abcdef1234'
        }
        throw new Error(`What is this? ${message}`)
    }
    
    const dispatch=(message:message):结果=>{
    if(克隆的消息实例){
    //做克隆人的事
    返回
    }
    如果(签出的消息实例){
    //结帐
    //我应该坚持让我在这里还空
    返回“不应允许”
    }
    if(RevParse的消息实例){
    const{branchName}=消息
    //做些什么
    返回“abcdef1234”
    }
    抛出新错误(`this是什么?${message}`)
    }
    

    这将修复您的第一个问题,Type Script现在将考虑返回<代码>调度(新克隆(URL))< /C>作为空白

    这可能是有用的:谢谢!给定一组这样的类型,有可能找出它们是否唯一吗?比如,我能防止人们在我的界面上编程时忘记让他们的类型独一无二吗?有没有办法测试它们的集合(元组或联合中的)是唯一的?如果您愿意,我可以单独问这个问题:)我认为这是不可能的,您是否尝试过这种方法:在这种情况下,您想要使用的任何类都应该实现您的命令接口。对不起,这取决于上下文
    // const checkoutResult: void
    
     const dispatch = <Message extends Protocol[0]>(message: Message): Result<Message> => {
        if (message instanceof Clone) {
            // do clone stuff
            return
        }
        if (message instanceof Checkout) {
            // do checkout stuff
    
            // should insist that I return void here
            return 'should not be allowed'
        }
        if (message instanceof RevParse) {
            const { branchName } = message
            // do revparse stuff
            return 'abcdef1234'
        }
        throw new Error(`What is this? ${message}`)
    }