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