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

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


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) 

UPDATE 2018-10-30

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

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  );}


It's very possible if you use ES6 Object.assign. Assuming you have existing objects of those types.

First let's define the types

interface ClientRequest {    userId:     number    sessionKey: string}interface Coords {    lat:  number    long: number}

Now the combination of both:

type Combined = ClientRequest & Coords;

Assuming you have two existing objects which you would like to pass to the function:

const foo: ClientRequest = {    userId: 10,    sessionKey: "gjk23h872ty3h82g2ghfp928ge"}const bar: Coords = {    lat: -23,    long: 52}

You can combine them like this:

const myData: Combined = Object.assign({}, foo, bar);

Or simply create a new one like this:

const myData: Combined = {    userId: 10,    sessionKey: "gjk23h872ty3h82g2ghfp928ge",    lat: -23,    long: 52,}

Previous method

Not type-safe.

The <Type> {...} syntax casts the object to the type specified in the angle brackets (Type), which bypasses Typescript's checker. See Type Assertion.

const 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?


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 ICoords interface (as in your question it looks more like a class) - rest easy - because an interface can extend a class too:

// Interface extending an interface and a classinterface 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.

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 x is either one or the other, not a combination of the two. Your syntax of a merged type IClientRequest & Coords isn't on the roadmap as far as I know.

function go(data: IClientRequest | Coords) {    var a = data[0]; // IClientRequest    var b = data[1]; // Coords}// Allowed (even though it doesn't supply Coords datago(myClientRequest);// Allowed (even though it doesn't supply IClientRequest datago (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 0 is an IClientRequest and element 1 is an Coords.

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

Uber-Annotation

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; } ) {}