似乎我想做的事情是不可能的,但我真的希望它是。
基本上,我有两个接口,我想将一个函数参数注释为两者的组合。
interface ClientRequest {
userId: number
sessionKey: string
}
interface Coords {
lat: number
long: number
}
然后,在函数中,我想做这样的事情:
function(data: ClientRequest&Coords) { ... }
这样我的数据' object可以包含两种类型的所有成员。
我在spec preview,"结合类型'中看到了引用的内容。会员",但似乎还没有成功。
如果不可能,我的解决方案可能如下所示:
interface ClientRequest<T> {
userId: number
sessionKey: string
data?: T
}
function(data: ClientRequest<Coords>) { ... }
在这种情况下会有效,尽管它不像我想的那样动态。我真的希望能够在注释本身中组合多种(2 +)类型:
function(data: TypeA&TypeB&TypeC) { ... }
我猜想传统的解决方案是定义一种扩展这些类型的类型,尽管这似乎不那么灵活。如果我想添加一个类型,我必须
任何TypeScript专家都指出我的方向正确吗?
答案 0 :(得分:30)
您的问题的具体答案是:不,没有一个内联注释来表示组合或扩展类型。
您尝试解决的问题的最佳做法是创建第三种类型,以扩展其他两种类型。
interface IClientRequestAndCoords extends IClientRequest, ICoords {}
function(data: IClientRequestAndCoords)
更新 2018-10-30
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
);
}
答案 1 :(得分:3)
接口答案是组合这两种结构的一种相当优雅的方法,但是您提到您想知道是否可以将该类型组合为注释的一部分。
我已经提供了与您的问题相关的一些功能的一些描述,但首先我要说的是,如果你因为认为你必须创建一个ICoords
接口而放弃接口解决方案(如在你的问题中,它看起来更像是一个类) - 休息很容易 - 因为接口也可以扩展一个类:
// Interface extending an interface and a class
interface IClientRequestAndCoords extends IClientRequest, Coords {}
接口甚至会合并属性,只要它们具有相同的名称和类型即可。 (例如,如果他们都声明了属性x: string
。
以下是您提到的其他注释功能的注释。
您可能已阅读的规范是联合类型,如下所示:
var x: IClientRequest | Coords;
但这只能确保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);
这也不是当前版本的一部分,但会在稍后发布。
您可能已经看到的规范的另一个可能部分是元组类型:
var x: [IClientRequest, Coords];
但是这会将数据的形状从一个结构改变为一个数组,其中元素0
是IClientRequest
而元素1
是Coords
。
function go(data: [IClientRequest, Coords]) {
var a = data[0]; // ClientRequest
var b = data[1]; // Coords
}
go([myClientRequest, myCoords]);
最后,如果你真的不想创建一个合并的界面,你可以使用超级注释:
function go(data: { userId:number; sessionKey: string; x: number; y: number; } ) {
}
答案 2 :(得分:2)
我在spec preview,&#34;结合类型&#39;中看到了引用的内容。会员&#34;,但似乎还没有成功。
我认为您对intersection
类型(不是union
)更感兴趣。不同之处在于传入的对象必须支持所有属性,而不是 之一。
Github问题:https://github.com/Microsoft/TypeScript/issues/1256#issuecomment-64533287
答案 3 :(得分:2)
如果您使用 ES6 Object.assign
interface ClientRequest {
userId: number
sessionKey: string
}
interface Coords {
lat: number
long: number
}
type Combined = ClientRequest & Coords;
然后您可以像这样定义数据:
let myData = Object.assign({},
<ClientRequest> {
userId: 10,
sessionKey: "gjk23h872ty3h82g2ghfp928ge"
},
<Coords> {
lat: -23,
long: 52
}
);
最后,调用函数:
function myFunc(data: Combined) { ... }
myFunc(myData);
有关更多实现此目的的方法,请参阅另一个问题:
How can I merge properties of two JavaScript objects dynamically?
答案 4 :(得分:0)
我只需要这样做,以下解决方案对我有用:
type MyFunction = () => void
interface MyFunctionWithProps extends MyFunction {
prop1: string,
prop2: number
}
// compiles fine
const MyMashup: MyFunctionWithProps = Object.assign(
() => {},
{
prop1: 'hello',
prop2: 1234
}
)
答案 5 :(得分:0)
现在,如果类型 P1 和 P2 扩展了对象,您可以使用条件类型执行类似操作:
type P1UnionP2 = { [k in (keyof P1 | keyof P2)]: k extends keyof P1 ? P1[k] : k extends keyof P2 ? P2[k] : never }
最好的方法是,如果这适用于您的情况,则:
interface P1UnionP2 extends P1, P2 { }