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