Können Sie mehrere Type Constraints für TypeScript-Generika angeben?

83

Ich habe eine generische Schnittstelle wie dieses Beispiel mit einer einzelnen Typeinschränkung:

export interface IExample<T extends MyClass> {
    getById(id: number): T;
}

Ist es möglich, mehrere Typbeschränkungen anstelle von nur einer anzugeben?

Fenton
quelle

Antworten:

87

Typescript bietet keine Syntax, um Mehrfachvererbung für generische Typen zu erhalten. Sie können jedoch eine ähnliche Semantik erzielen, indem Sie die Unionstypen und Schnittpunkttypen verwenden. In Ihrem Fall möchten Sie eine Kreuzung:

interface Example<T extends MyClass & OtherClass> {}

Für eine Union beider Typen:

interface Example<T extends MyClass | OtherClass> {}
STO
quelle
4
Union-Typen sind eine großartige Möglichkeit, um dies zu erreichen, da Sie keine Schnittstelle nur für den Zweck der Einschränkung erstellen müssen. Sie existierten 2013 noch nicht - aber so würde ich es jetzt definitiv empfehlen.
Fenton
5
Diese Antwort ist falsch. Unionstypen haben nicht die gleiche Semantik wie die Erweiterung zweier unterschiedlicher Typen.
AlexG
3
@AlexG Sicher ist dies nicht dasselbe wie das Erweitern von zwei Typen, sondern dasselbe wie das Implementieren von zwei Schnittstellen.
STO
6
Beachten Sie auch, dass Typescript auch Schnittpunkttypen unterstützt. So <T extends MyInterfaceA & MyInterfaceB>erfordert , dass die Art , beide Schnittstellen implementieren.
Tyler Cloutier
2
Soweit ich die Semantik von extends A|Bis verstehe, erstreckt sich A ODER B ebenso wie extends A & Bbeide! Vielleicht sollten Sie beide in Ihrer Antwort angeben ...
Pipo
34

Eine Lösung hierfür wäre die Verwendung einer Super-Schnittstelle (die auch die Frage beantwortet, warum eine Schnittstelle von einer Klasse erben darf).

interface ISuperInterface extends MyClass, OtherClass {

}

export interface IExample<T extends ISuperInterface> {
    getById(id: number): T;
}
Fenton
quelle
12
Dies ist die richtige Lösung. Das Erweitern einer Schnittstelle aus zwei Klassen ist beängstigend, obwohl - wenn beide private Mitglieder deklarieren, die Schnittstelle nicht
Ryan Cavanaugh am
1

Verweisen Sie auf den Kommentar zu einer Schnittstelle, die von einer Klasse stammt ... was ist in einem Namen?

Ich fand dies in Abschnitt 3.5 der 0.9.0-Spezifikation:

Schnittstellendeklarationen führen nur benannte Typen ein, während Klassendeklarationen benannte Typen und Konstruktorfunktionen einführen, die Instanzen von Implementierungen dieser benannten Typen erstellen. Die durch Klassen- und Schnittstellendeklarationen eingeführten benannten Typen weisen nur geringfügige Unterschiede auf (Klassen können keine optionalen Mitglieder deklarieren und Schnittstellen können keine privaten Mitglieder deklarieren) und sind in den meisten Kontexten austauschbar. Insbesondere Klassendeklarationen mit nur öffentlichen Mitgliedern führen benannte Typen ein, die genau so funktionieren, wie sie durch Schnittstellendeklarationen erstellt wurden.

andyks
quelle
Optionale Klassenmitglieder sind jetzt implementiert: github.com/Microsoft/TypeScript/pull/8625
Stefan Rein