Javascript 是否可以在 TypeScript 注释中组合多种类型的成员?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27325524/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 00:01:53  来源:igfitidea点击:

Is it possible to combine members of multiple types in a TypeScript annotation?

javascripttypescriptinterface

提问by Joshua

It seems that what I am trying to do is not possible, but I really hope it is.

似乎我正在尝试做的事情是不可能的,但我真的希望它是。

Essentially, I have two interfaces, and I want to annotate a single function parameter as the combination of both of them.

本质上,我有两个接口,我想将单个函数参数注释为它们的组合。

interface ClientRequest {
    userId:     number
    sessionKey: string
}

interface Coords {
    lat:  number
    long: number
}

And then, in the function, I want to do something like this:

然后,在函数中,我想做这样的事情:

function(data: ClientRequest&Coords) { ... }

So that my 'data' object could contain all of the members from both types.

这样我的“数据”对象就可以包含这两种类型的所有成员。

I saw something referenced in a spec preview, under "Combining Types' Members", but it seems like this hasn't made it in yet.

我在“组合类型的成员”下的规范预览中看到了一些引用,但似乎这还没有实现。

If it isn't possible, my solution might look like this:

如果不可能,我的解决方案可能如下所示:

interface ClientRequest<T> {
    userId:     number
    sessionKey: string
    data?:       T
}

function(data: ClientRequest<Coords>) { ... }

Which would work in this case, although it's not as dynamic as I would like. I would really like to be able to combine multiple (2+) types in the annotation itself:

这在这种情况下会起作用,尽管它不像我想要的那样动态。我真的希望能够在注释本身中组合多个 (2+) 类型:

function(data: TypeA&TypeB&TypeC) { ... }

I would guess that the conventional solution is to define a type that extends those types, although that seems less flexible. If I want to add a type, I would have to either

我猜传统的解决方案是定义一个扩展这些类型的类型,尽管这似乎不太灵活。如果我想添加一个类型,我必须要么

  • (a) go back to the declaration and rewrite it, or
  • (b) create an entirely new interface. Not sure I agree with the extra overhead.
  • (a) 回到声明并重写它,或
  • (b) 创建一个全新的界面。不确定我是否同意额外的开销。

Any TypeScript experts care to point me in the right direction?

有没有 TypeScript 专家愿意为我指明正确的方向?

回答by Martin

The specific answer to your question is: no, there is not a single inline annotation to signify combined or extended types.

您问题的具体答案是:不,没有单个内联注释来表示组合类型或扩展类型。

The best practice for the problem you are trying to solve would be to create third type that would extend the other two.

您尝试解决的问题的最佳实践是创建第三种类型来扩展其他两种类型。

interface IClientRequestAndCoords extends IClientRequest, ICoords {} 

function(data: IClientRequestAndCoords) 

UPDATE2018-10-30

更新2018-10-30

TypeScript now has type intersections. So you can now simply do:

TypeScript 现在有类型交叉。所以你现在可以简单地做:

interface ClientRequest {
  userId:     number
  sessionKey: string
}

interface Coords {
  lat:  number
  long: number
}

function log(data: ClientRequest & Coords) { 
  console.log(
    data.userId,
    data.sessionKey,
    data.lat,
    data.long
  );
}

回答by Fenton

The interface answer is a reasonably graceful method of combining the two structures, but you mention that you want to know if it is possible to combine the type as part of an annotation.

接口答案是将两种结构组合在一起的一种相当优雅的方法,但是您提到您想知道是否可以将类型组合为注释的一部分。

A note on interfaces

接口注意事项

I have supplied some descriptions of a few features related to your question, but first I would say that if you are put off of the interface solution because you think you'll have to create an ICoordsinterface (as in your question it looks more like a class) - rest easy - because an interface can extend a class too:

我已经提供了与您的问题相关的一些功能的一些描述,但首先我想说的是,如果您因为认为必须创建一个ICoords界面而放弃界面解决方案(如在您的问题中,它看起来更像是一个class) - 轻松一点 - 因为接口也可以扩展类:

// Interface extending an interface and a class
interface IClientRequestAndCoords extends IClientRequest, Coords {} 

The interface will even merge properties as long as they have the same name and type. (For example if they both declared a property x: string.

只要属性具有相同的名称和类型,该接口甚至会合并它们。(例如,如果他们都声明了一个属性x: string.

Here are notes on the other annotation features you allude to.

以下是您提到的其他注释功能的说明。

Union Types

联合类型

The specification you may have read is the union type, which looks like this:

你可能读过的规范是联合类型,它看起来像这样:

var x: IClientRequest | Coords;

But this only ensures that xis either one or the other, not a combination of the two. Your syntax of a merged type IClientRequest & Coordsisn't on the roadmap as far as I know.

但这只能确保x是其中之一,而不是两者的组合。IClientRequest & Coords据我所知,您的合并类型的语法不在路线图上。

function go(data: IClientRequest | Coords) {
    var a = data[0]; // IClientRequest
    var b = data[1]; // Coords
}

// Allowed (even though it doesn't supply Coords data
go(myClientRequest);

// Allowed (even though it doesn't supply IClientRequest data
go (myCoords);

This also isn't part of the current release, but is coming later.

这也不是当前版本的一部分,但稍后会发布。

Tuple Types

元组类型

Another possible part of the specification you may have seen is tuple types:

您可能已经看到的规范的另一个可能部分是元组类型:

var x: [IClientRequest, Coords];

But this would change the shape of the data from being a structure to being like an array where element 0is an IClientRequestand element 1is an Coords.

但这会将数据的形状从结构更改为数组,其中 element0是 an IClientRequest, element1是 an Coords

function go(data: [IClientRequest, Coords]) {
    var a = data[0]; // ClientRequest
    var b = data[1]; // Coords
}

go([myClientRequest, myCoords]);

Uber-Annotation

Uber-注解

And finally, if you really don't want to create a merged interface, you could just use an uber-annotation:

最后,如果你真的不想创建一个合并的界面,你可以使用一个超级注释:

function go(data: { userId:number; sessionKey: string; x: number; y: number; } ) {

}

回答by basarat

I saw something referenced in a spec preview, under "Combining Types' Members", but it seems like this hasn't made it in yet.

我在“组合类型的成员”下的规范预览中看到了一些引用,但似乎这还没有实现。

I think you would be more interested in intersectiontypes (not union). The difference is that the object passed in must support allof the properties and not one of.

我认为您会对intersection类型更感兴趣(不是union)。不同之处在于传入的对象必须支持所有属性,而不是其中之一

Github issue : https://github.com/Microsoft/TypeScript/issues/1256#issuecomment-64533287

Github 问题:https: //github.com/Microsoft/TypeScript/issues/1256#issuecomment-64533287

回答by smac89

It's very possible if you use ES6Object.assign

如果你使用ES6很有可能Object.assign

interface ClientRequest {
    userId:     number
    sessionKey: string
}

interface Coords {
    lat:  number
    long: number
}

type Combined = ClientRequest & Coords;

Then you can define your data like this:

然后你可以像这样定义你的数据:

let myData = Object.assign({},
    <ClientRequest> {
        userId: 10,
        sessionKey: "gjk23h872ty3h82g2ghfp928ge"
    },
    <Coords> {
        lat: -23,
        long: 52
    }
);

Finally, call the function:

最后,调用函数:

function myFunc(data: Combined) { ... }
myFunc(myData);


See this other question for even more ways of accomplishing this:

有关完成此操作的更多方法,请参阅另一个问题:

How can I merge properties of two JavaScript objects dynamically?

如何动态合并两个 JavaScript 对象的属性?

回答by James Trickey

I just needed to do this and the following solution worked for me:

我只需要这样做,以下解决方案对我有用:

type MyFunction = () => void

interface MyFunctionWithProps extends MyFunction {
  prop1: string,
  prop2: number
}

// compiles fine
const MyMashup: MyFunctionWithProps = Object.assign(
  () => {},
  {
    prop1: 'hello',
    prop2: 1234
  }
)