javascript - Wann man Typen (vs Schnittstelle) in TS verwendet
Ich kann nicht verstehen, wann, falls überhaupt, du einen type anstelle eines interface für eine Variable in TypeScript verwenden möchtest. Gehe von den folgenden beiden aus:
type User = {
id: string;
name: string;
type: string;
}
interface User {
id: string;
name: string;
type: string;
}
Ich kann eine Variable genau auf die gleiche Weise definieren const user: User=.... Allerdings sind hier alle Dinge, die ich mit interface tun kann, die ich mit types nicht tun kann:
// Extension:
interface AdminUser extends User {
permissions: string[];
role: string;
}
// Using in abstract method:
abstract class Home {
abstract login(user: User): void;
}
class AdminHome extends Home {
login(user: AdminUser) {
...
}
}
Um nur einige zu nennen.
Also ist meine Frage: Wann würde man jemals einen type verwenden wollen?
Antwort #1
BEARBEITUNG (15.12.2020): Ganz unten habe ich Informationen zu „Typen“ in TS (oder dem entsprechenden Konzept in einer anderen Sprache) hinzugefügt.
Wenn ich mich nicht irre, ist dir nicht ganz klar, was der Zweck einer Schnittstelle im Vergleich zu einem Typ ist.
In OOP-Begriffen haben Schnittstellen keine Implementierungen. Typen haben das. Eine Schnittstelle ist also im Grunde nutzlos, es sei denn, ein Typ implementiert sie. Außerdem kann ein Typ nur einen anderen Typ erweitern. Aber er kann viele Schnittstellen implementieren.
Aber was bedeutet das...
Angenommen, Sie haben ein Auto und einen Benutzer. Sehr unterschiedliche Typen, bei denen man nicht sofort denkt, dass sie auf praktische Weise dasselbe sind. Manche könnten sagen: „Nun, Sie sollten ICar und IUser erstellen“. Aber wirklich, das ist einfach keine praktische Art, über Schnittstellen nachzudenken. Es wäre verwirrend für den Benutzer, ICar zu implementieren, und/oder ICar scheint einfach dasselbe zu tun wie Car. Was wäre für einen anderen Programmierer, der sich den Code ansieht, der Unterschied?
Angenommen, du möchtest, dass beide (wieder nur der Lust halber) "Selbstbeschreibbar" sind, und du möchtest, dass beide die Informationen auf die gleiche Weise bereitstellen. Also würdest du erstellen:
ISelfDescribable {
getSelfDescription ( );
}
Jetzt würdest du das tun:
Car implements ISelfDescribable {
getSelfDescription ( return "I am a car!" );
}
User implements ISelfDescribable {
getSelfDescription ( return ...some other completely different way of getting the info... );
}
Ein Array dieser Objekte wäre (denken Sie darüber nach, wie Sie dies sonst ohne Schnittstellen tun würden):
Array<ISelfDescribable>
Jetzt weißt du (und jeder andere Entwickler, der sich den Code ansieht) mit Sicherheit, dass jedes Objekt in diesem Array, unabhängig vom konkreten Typ, das "Verhalten" von ISelfDesribable implementiert. Wenn man darüber nachdenkt, gibt es wirklich keinen Grund, jemals zu wissen, welchen Typ es hat, es sei denn, man implementiert ihn; man interessiert sich nur für das Verhalten. Aber man braucht dennoch den Typ, um dieses Verhalten zu implementieren.
Angenommen, eines Tages möchtest du, dass beide Objekte „versicherbar“ sind. Sie sollten beide eine Methode „setInsurancePolicy“ haben. Du könntest IInsurable { setInsurancePolicy ( policy : Policy ) } erstellen und sie in den Typen implementieren. Jetzt hast du Objekte, die sowohl ISelfDescribable als auch IInsurable sind, und du kannst ein Array dieser Objekte als eines von beiden typisieren.
Für mich ging das große Licht auf, als ich verstanden habe: Typen (und Typ-Hierarchien) sollten sich mit konkreten Dingen befassen. Schnittstellen sollten sich mit Verhalten befassen, das zwischen verschiedenen Typen geteilt werden kann. Es gibt noch mehr dazu, aber das vermittelt zumindest eine Vorstellung davon, warum man eine Schnittstelle oder einen Typ wählen würde. Sie repräsentieren unterschiedliche Dinge im Programmieren, auch wenn sie sonst gleich erscheinen.
(Nachtrag: Sprachen wie Scala denken nicht in Bezug auf Schnittstellen auf diese Weise. Sie haben zwar ein Konzept von „Verhalten“, aber man kann auch Verhaltensweisen implementieren und überschreiben. Das ist vielleicht zu viel akademisches Geschwafel für diese spezielle Frage, aber hey, ich muss alle Monster im Dungeon töten, nicht nur die für die Quest).
15.12.2020: TypeScript: Typen vs. Schnittstellen.
Warum das eine oder das andere verwenden? Es hängt wieder davon ab, was Sie damit darstellen möchten und wie genau Sie es verwenden wollen.
Ein „Typ“ ist die Antwort „Ich brauche einen Vertrag, aber es ist keine Verhaltensdefinition wie ein Interface“.
Dies ermöglicht es Ihnen, die Differenzierung semantisch beizubehalten. Dies ist ein Interface, weil es ein horizontales Verhalten definiert. Dies ist ein Typ, weil es... einen Typ definiert.
Weiter in dieser Richtung sind Typen jedoch funktional-freundlich auf eine Weise, wie Schnittstellen es nicht sind, weil man Typen kombinieren und schneiden kann. In React zum Beispiel habe ich gehört, dass gesagt wird: ‚Verwende niemals Schnittstellen, weil sie bei weitem nicht so zusammensetzbar sind wie Typen.‘
Angenommen, Sie haben zwei Serviceaufrufe und möchten einen Vertrag für die Nutzlasten festlegen. Schnittstelle? Nein... das ist für horizontale Verhaltensweisen. Aber ein „Typ“, ja... er typisiert die Nutzlast, definiert jedoch semantisch kein Verhalten.
Und nehmen wir an, Sie stoßen auf die häufige Aufgabe, die Definitionen von zwei Payload-Typen in einen zu zusammenzuführen (für eine UI-Komponente oder so etwas). Mit "type"-Definitionen macht die Sprache diese Art von Vereinigung/Schnittmenge/etc. unkompliziert.
Also stimmt die Logik immer noch; Schnittstellen, horizontales Verhalten, Typen, vertikale Definitionen, die auf verschiedene Weisen kombiniert werden können.
