Die 5 Gebote von TypeScript Developer

Bild


Immer mehr Projekte und Teams verwenden TypeScript. Nur TypeScript anzuwenden und das Beste daraus herauszuholen, ist jedoch etwas ganz anderes.


Ich präsentiere Ihnen eine Liste allgemeiner Best Practices für die Verwendung von TypeScript, mit denen Sie diese Sprache optimal nutzen können.


Lüg nicht


Typen ist ein Vertrag. Was bedeutet das? Wenn Sie eine Funktion implementieren, wird ihr Typ zu einem Versprechen für andere Entwickler (oder für sich selbst in der Zukunft!), Dass diese Funktion beim Aufruf einen bestimmten Werttyp zurückgibt.


Im folgenden Beispiel stellt der Typ der Funktion getUser sicher, dass ein Objekt zurückgegeben wird, das immer zwei Eigenschaften hat: name und age .


 interface User { name: string; age: number; } function getUser(id: number): User { /* ... */ } 

TypeScript ist eine sehr flexible Sprache. Es gibt viele Kompromisse, die die Einführung der Sprache erleichtern sollen. So können Sie beispielsweise die Funktion getUser implementieren:


 function getUser(id: number): User { return { age: 12 } as User; } 

Tu das nicht! Das ist eine Lüge. Durch das Erstellen eines solchen Codes LIEGEN Sie andere Entwickler (die Ihre Funktion in ihren Funktionen verwenden). Sie erwarten, dass das von getUser Objekt immer eine Art getUser . Aber er ist nicht da! Was passiert außerdem, wenn Ihr Kollege getUser(1).name.toString() schreibt? Sie wissen sehr gut, dass ...


Hier scheint die Lüge natürlich offensichtlich. Wenn Sie jedoch mit einer großen Codebasis arbeiten, befinden Sie sich häufig in Situationen, in denen der Wert, den Sie zurückgeben (oder übergeben) möchten, fast dem erwarteten Typ entspricht. Es braucht Zeit und Mühe, um die Ursache für die Typinkongruenz zu finden , und Sie haben es eilig ... also entscheiden Sie sich für Typguss.


Auf diese Weise brechen Sie jedoch den heiligen Vertrag . Es ist IMMER besser, sich die Zeit zu nehmen und zu verstehen, warum die Typen nicht übereinstimmen, als Typguss zu verwenden. Es ist sehr wahrscheinlich, dass sich ein Laufzeitfehler unter der Oberfläche versteckt.


Lüge nicht. Befolgen Sie Ihre Verträge.


Sei genau


Typen sind Dokumentation. Möchten Sie bei der Dokumentation einer Funktion nicht so viele Informationen wie möglich vermitteln?


 //   function getUser(id) { /* ... */ } //     : name  age function getUser(id) { /* ... */ } //  id       id , //     : name  age. //     undefined. function getUser(id) { /* ... */ } 

Welchen Kommentar zur getUser Funktion getUser Sie mehr? Je mehr Sie wissen, dass eine Funktion zurückkehrt, desto besser. Wenn Sie beispielsweise wissen, dass es undefined , können Sie einen if Block schreiben, um zu überprüfen, ob das von der Funktion zurückgegebene Objekt definiert ist, bevor Sie die Eigenschaften dieses Objekts anfordern.


Genau das Gleiche gilt für Typen: Je genauer ein Typ beschrieben wird, desto mehr Informationen werden übermittelt.


 function getUserType(id: number): string { /* ... */ } function getUserType(id: number): 'standard' | 'premium' | 'admin' { /* ... */ } 

Die zweite Version der Funktion getUserType viel informativer, und daher befindet sich der Anrufer in einer viel bequemeren Situation. Es ist einfacher, den Wert zu verarbeiten, wenn Sie wahrscheinlich wissen (Verträge, erinnern Sie sich?), Dass es sich um eine der drei angegebenen Zeilen handelt und nicht um irgendeine Zeile. Um mit dem zu beginnen, was Sie sicher wissen - ein Wert kann keine leere Zeichenfolge sein.


Betrachten wir ein realeres Beispiel. Der Statustyp beschreibt den Status der Komponente, die einige Daten vom Backend anfordert. Ist dieser Typ genau?


 interface State { isLoading: boolean; data?: string[]; errorMessage?: string; } 

Ein Client, der diesen Typ verwendet, muss eine unwahrscheinliche Kombination von Statuseigenschaftswerten verarbeiten. Beispielsweise ist eine Situation nicht möglich, wenn die Eigenschaften data und errorMessage gleichzeitig definiert werden: Eine errorMessage kann entweder erfolgreich sein oder fehlschlagen.


Wir können den Typ mit Hilfe diskriminierter Gewerkschaftstypen viel genauer machen:


 type State = | { status: 'loading' } | { status: 'successful', data: string[] } | { status: 'failed', errorMessage: string }; 

Jetzt hat der Client, der diesen Typ verwendet, viel mehr Informationen: Er muss keine falschen Eigenschaftskombinationen mehr verarbeiten.


Sei genau. Geben Sie so viele Informationen wie möglich über Ihre Typen weiter.


Beginnen Sie mit Typen


Da Typen sowohl Vertrag als auch Dokumentation sind, eignen sie sich hervorragend zum Entwerfen Ihrer Funktionen (oder Methoden).


Es gibt viele Artikel im Internet, die Programmierern raten , vor dem Schreiben von Code nachzudenken . Ich teile diesen Ansatz voll und ganz. Die Versuchung, direkt zum Code zu springen, ist groß, aber dies führt oft zu schlechten Entscheidungen. Ein wenig Zeit zum Nachdenken über die Implementierung zahlt sich immer gut aus.


Typen sind in diesem Prozess äußerst nützlich. Denken führt zur Erstellung von Signaturen von Funktionstypen, die sich auf die Lösung Ihres Problems beziehen. Und das ist großartig, weil Sie sich darauf konzentrieren, was Ihre Funktionen tun, anstatt darüber nachzudenken, wie sie es tun.


React JS hat das Konzept eines Higher Order Components (HOC). Dies sind Funktionen, die die angegebene Komponente in irgendeiner Weise erweitern. Beispielsweise können Sie mit withLoadingIndicator eine Komponente höherer Ordnung withLoadingIndicator , die einer vorhandenen Komponente einen withLoadingIndicator hinzufügt.


Schreiben wir eine Typensignatur für diese Funktion. Die Funktion akzeptiert eine Komponenteneingabe und gibt auch eine Komponente zurück. Um eine Komponente darzustellen, können wir den Typ React ComponentType verwenden.


ComponentType ist ein generischer Typ, der durch den Typ der Komponenteneigenschaften parametrisiert wird. withLoadingIndicator akzeptiert eine Komponente und gibt eine neue Komponente zurück, die entweder die ursprüngliche Komponente oder den withLoadingIndicator anzeigt. Die Entscheidung darüber, was angezeigt werden soll, basiert auf dem Wert der neuen logischen Eigenschaft - isLoading . Daher benötigt die zurückgegebene Komponente dieselben Eigenschaften wie die ursprüngliche, nur die neue isLoading Eigenschaft wird hinzugefügt.


Wir werden den Typ finalisieren. withLoadingIndicator akzeptiert eine Komponente vom Typ ComponentType<P> , wobei P den Typ der Eigenschaft bezeichnet. withLoadingIndicator gibt eine Komponente mit erweiterten Eigenschaften vom Typ P & { isLoading: boolean } .


 const withLoadingIndicator = <P>(Component: ComponentType<P>) : ComponentType<P & { isLoading: boolean }> => ({ isLoading, ...props }) => { /* ... */ } 

Beim Umgang mit den Arten von Funktionen mussten wir darüber nachdenken, was auf dem Eingang und was auf dem Ausgang sein wird. Mit anderen Worten, wir mussten eine Funktion entwerfen . Das Schreiben der Implementierung ist jetzt einfach.


Beginnen Sie mit Typen. Lassen Sie sich von den Typen zwingen, zuerst zu entwerfen und erst dann die Implementierung zu schreiben.


Nehmen Sie Strenge


Bei den ersten drei Geboten müssen Sie den Typen besondere Aufmerksamkeit schenken. Glücklicherweise müssen Sie bei der Lösung dieses Problems nicht alles selbst erledigen. Oft teilt Ihnen der TypeScript-Compiler mit, wann Ihre Typen lügen oder wann sie nicht genau genug sind.


Sie können dem Compiler dabei helfen, dies noch besser zu machen, indem Sie das Flag --strict . Dies ist ein Meta-Flag, --noImplicitAny alle strengen Optionen für die --noImplicitAny --noImplicitThis : --noImplicitAny , --noImplicitThis , --alwaysStrict , --strictBindCallApply , --strictNullChecks , --strictFunctionTypes und --strictPropertyInitialization .


Was machen die Flaggen? Im Allgemeinen führt ihre Einbeziehung zu einer Zunahme der Anzahl von TypeScript-Kompilierungsfehlern. Und das ist gut! Mehr Kompilierungsfehler - mehr Hilfe vom Compiler.


Mal sehen, wie das --strictNullChecks Flags --strictNullChecks beiträgt, einen --strictNullChecks im Code zu erkennen.


 function getUser(id: number): User { if (id >= 0) { return { name: 'John', age: 12 }; } else { return undefined; } } 

Der Typ getUser stellt sicher, dass die Funktion immer ein Objekt vom Typ User zurückgibt. Schauen Sie sich jedoch die Implementierung an: Eine Funktion kann auch undefined !


Glücklicherweise führt das Aktivieren des --strictNullChecks zu einem Kompilierungsfehler:


 Type 'undefined' is not assignable to type 'User'. 

Der TypeScript-Compiler erkennt Unwahrheiten. Um diesen Fehler zu beseitigen, sagen Sie einfach ehrlich die ganze Wahrheit:


 function getUser(id: number): User | undefined { /* ... */ } 

Akzeptieren Sie die strenge Typprüfung. Lassen Sie sich vom Compiler vor Fehlern schützen.


Bleiben Sie auf dem Laufenden


TypeScript entwickelt sich sehr schnell. Alle zwei Monate wird eine neue Version veröffentlicht. Jede Version bringt bedeutende Sprachverbesserungen und neue Funktionen.


Es kommt häufig vor, dass Sie mit den neuen Funktionen der Sprache Typen genauer definieren und genauer prüfen können.


Zum Beispiel wurden in Version 2.0 diskriminierte Unionstypen eingeführt (ich habe sie im Gebot „ Genau sein“ erwähnt ).


In Version 3.2 wurde das Compiler-Flag --strictBindCallApply , das die korrekte Eingabe für die Funktionen zum bind , call und --strictBindCallApply enthält.


Version 3.4 verbesserte die Typinferenz in Funktionen höherer Ordnung , wodurch es einfacher wurde, exakte Typen beim Schreiben von Code in einem funktionalen Stil zu verwenden.


Mein Standpunkt ist, dass es sich tatsächlich lohnt, die in neueren Versionen von TypeScript eingeführten Sprachfunktionen kennenzulernen. Oft kann dies Ihnen helfen, die anderen vier Gebote aus der Liste zu befolgen.


Ein guter Ausgangspunkt ist die offizielle TypeScript-Roadmap . Es wird auch schön sein, regelmäßig den TypeScript-Abschnitt in Microsoft Devblog zu überprüfen, da alle Release-Ankündigungen dort abgelegt werden.


Bleiben Sie über die neuen Funktionen der Sprache auf dem Laufenden und lassen Sie dieses Wissen für Sie arbeiten.


Zusammenfassung


Ich hoffe, Sie finden die Liste hilfreich. Wie immer und in allem sollte man diese Gebote nicht blind befolgen. Ich bin jedoch der festen Überzeugung, dass Sie mit diesen Regeln ein besserer TypeScript-Entwickler werden.


Ich werde mich freuen, Ihre Gedanken zu diesem Thema in den Kommentaren zu sehen.


Bonus


Hat Ihnen dieser Artikel über TypeScript gefallen? Ich bin sicher, dass Ihnen auch dieses kostenlose PDF gefallen wird: 10 TypeScript-Entwicklungsfehler, die Ihren Code unsicher machen.

Source: https://habr.com/ru/post/de461565/


All Articles