2014-12-05 3 views
10

Es scheint, dass das, was ich versuche, nicht möglich ist, aber ich hoffe es wirklich.Ist es möglich, Elemente mehrerer Typen in einer TypeScript-Annotation zu kombinieren?

Im Wesentlichen habe ich zwei Schnittstellen, und ich möchte einen einzelnen Funktionsparameter als die Kombination von beiden annotieren.

interface ClientRequest { 
    userId:  number 
    sessionKey: string 
} 

interface Coords { 
    lat: number 
    long: number 
} 

Und dann, in der Funktion, möchte ich so etwas wie dies zu tun:

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

Damit meine ‚Daten‘ Objekt alle Mitglieder aus beiden Typen enthalten könnten.

Ich sah etwas referenziert in einer (spec preview) [https://github.com/Microsoft/TypeScript/issues/805], unter "Combining Typen 'Mitglieder", aber es scheint, als ob dies noch nicht gemacht hat.

Wenn es nicht möglich ist, könnte meine Lösung so aussehen:

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

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

die in diesem Fall funktionieren würde, auch wenn es nicht so dynamisch ist wie Ich mag würde. Ich würde wirklich in der Lage sein möge, um mehr (2+) Arten in der Anmerkung selbst zu kombinieren:

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

Ich würde vermuten, dass die herkömmliche Lösung ist eine Art zu definieren, die diese Typen erweitert, aber das ist weniger flexibel zu sein scheint. Wenn ich einen Typ hinzufügen möchte, müsste ich entweder (a) zu der Deklaration zurückkehren und sie neu schreiben, oder (b) eine völlig neue Schnittstelle erstellen. Nicht sicher, ich stimme dem zusätzlichen Overhead zu.

Irgendwelche TypeScript-Experten wollen mich in die richtige Richtung weisen?

Antwort

15

Die spezifische Antwort auf Ihre Frage lautet: Nein, es gibt keine einzige Inline-Annotation, die kombinierte oder erweiterte Typen kennzeichnet.

Die beste Vorgehensweise für das Problem, das Sie versuchen zu lösen, wäre, einen dritten Typ zu erstellen, der die anderen beiden erweitert.

interface IClientRequestAndCoords extends IClientRequest, ICoords {} 

function(data: IClientRequestAndCoords) 
+0

Das ist der einzige Weg zu gehen zu sein scheint. Es ist einfach viel wortreicher als ich mir erhofft hatte. – Joshua

+1

Dies sollte die akzeptierte Antwort sein;) – basarat

+0

Während es ein guter Vorschlag ist, und wahrscheinlich der richtige Weg zu gehen, beantwortet es nicht wirklich die Frage, die ist "Ist es möglich, Typen in einer Anmerkung zusammenzufassen?" Die Implikation ist, dass es nicht ist, aber ich warte auf eine explizite Antwort. – Joshua

3

Die Schnittstelle Antwort ist ein recht graziös Verfahren die beiden Strukturen zu kombinieren, aber Sie erwähnen, dass Sie wissen wollen, ob es möglich ist, die Art als Teil einer Anmerkung zu kombinieren.

Ein Hinweis auf Schnittstellen

ich einige Beschreibungen von einigen Funktionen Ihrer Frage geliefert haben, aber ich würde zunächst sagen, dass, wenn Sie aus der Interface-Lösung setzen, weil Sie denken, dass Sie erstellen müssen eine ICoords Schnittstelle (wie in Ihrer Frage es eher wie eine Klasse aussieht) - ruhig schlafen - weil eine Schnittstelle zu einer Klasse erweitern kann:

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

die Schnittstelle wird auch Eigenschaften fusionieren, solange sie die gleichen Namen haben und Art. (Zum Beispiel, wenn beide eine Eigenschaft deklarierten x: string.

Hier sind Hinweise zu den anderen Annotation Features, auf die Sie anspielen.

Union Typen

Die Spezifikation, die Sie gelesen haben kann, ist die Art Gewerkschaft, die wie folgt aussieht:

var x: IClientRequest | Coords; 

Aber dies stellt nur sicher, dass x entweder das eine oder das andere ist, nicht eine Kombination aus die Zwei. Ihre Syntax eines zusammengeführten Typs IClientRequest & Coords ist soweit ich weiß nicht auf der Roadmap.

Dies ist auch nicht Teil der aktuellen Version, aber kommt später.

Tuple Typen

Ein weiterer möglicher Teil der Spezifikation Du Tupel-Typen gesehen haben sind:

var x: [IClientRequest, Coords]; 

Dies würde aber die Form der Daten von ändert eine Struktur zu sein, wie ein Array sein, wo Element 0 ist ein IClientRequest und Element 1 ist ein Coords.

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

go([myClientRequest, myCoords]); 

Uber-Annotation

Und schließlich, wenn Sie wirklich eine fusionierte Schnittstelle zu schaffen, nicht möchten, können Sie einfach eine uber-Anmerkung verwenden:

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

} 
+0

So funktioniert die vorgeschlagene Vereinigungsfunktion nicht. In Ihrem Beispiel für die Funktion go (data: IClientRequest | Coords) ist der Wert der Daten kein Array oder Tupel, sondern ein Objekt, das beide Interfaces erfüllt. Es wäre dann Aufgabe der Funktion, es herauszufinden, zB: if (data.hasOwnProperty ('userId') {// muss IClientRequest sein – Martin

+0

@Martin - Ich kann nicht widersprechen, weil ich denke, das ist genau das, was ich gesagt habe ?! 'Aber das stellt nur sicher, dass x entweder das eine oder das andere ist, nicht eine Kombination der beiden. ' – Fenton

+1

yep. Du hast recht. Ich habe es wieder gelesen, das hast du gesagt :) Irgendwie habe ich bei meinen vorherigen Lesungen den Code falsch verstanden Beispiel auf Tuples als eine Fortsetzung auf, wie Sie dann die Vereinigung in einer Funktion verwenden würden. Meine schlechte, wie sie in den 90er Jahren sagten. – Martin

1

ich sah, etwas referenziert in einer (spec preview) [https://github.com/Microsoft/TypeScript/issues/805], unter "Combining Types 'Mitglieder", aber es scheint, als ob dies noch nicht gemacht hat.

Ich glaube, Sie würden in intersection Typen mehr daran interessiert sein (nicht union). Der Unterschied ist, dass das übergebene Objekt alle der Eigenschaften unterstützen muss und nicht eins von.

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

+0

Ja. Genau das habe ich mir erhofft. – Joshua

2

Es ist sehr möglich, wenn Sie ES6Object.assign

interface ClientRequest { 
    userId:  number 
    sessionKey: string 
} 

interface Coords { 
    lat: number 
    long: number 
} 

type Combined = ClientRequest & Coords; 

Dann können Sie Ihre Daten wie folgt definieren:

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

Schließlich rufen Sie die Funktion :

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

Sehen Sie diese andere Frage für noch mehr Möglichkeiten, dies zu erreichen:

How can I merge properties of two JavaScript objects dynamically?

+1

Sie können die 'ClientRequest & Coords' auch einfach inline platzieren, so:' function myFunc (data: ClientRequest & Coords) {} ' – Venryx

Verwandte Themen