Einführung in TypeScript
Veröffentlicht: 2020-10-29Die ersten Sprachen, mit denen ich je programmiert habe, waren C und Java. Bei diesen Sprachen müssen Sie jedes Mal, wenn Sie eine Variable definieren, ihren Typ angeben. Wenn Sie versuchen, ihm einen Wert eines anderen Typs zuzuweisen, beschwert sich der Compiler:
// main.c int main() { int x = "two"; return 0; } > cc main.c -o main // warning: initialization makes integer from pointer without a castDas Problem ist, dass aufgrund meiner mangelnden Erfahrung viele der Beschwerden, die ich vom Compiler erhielt, kryptisch und komplex aussahen. Deshalb habe ich den Compiler letztendlich als ein Werkzeug betrachtet, das meine Kreativität einschränkt, obwohl er eigentlich ein Partner sein sollte, der da ist, um zu helfen.

Später in meiner Karriere fing ich an, einige Programmiersprachen ohne starkes Tippen zu verwenden, wie JavaScript oder PHP. Ich fand sie ziemlich cool: Es war extrem einfach, schnell Prototypen zu erstellen, ohne sich mit einem wählerischen Compiler herumschlagen zu müssen.
Wie Sie bereits wissen, sind die Programmiersprachen, auf denen WordPress basiert, PHP und JavaScript. Das bedeutet, dass Sie es wahrscheinlich gewohnt sind, Ihre Plugins und Themes zu programmieren, ohne dass ein Compiler Ihnen den Rücken freihält. Es sind nur Sie, Ihre Fähigkeiten und Ihre Kreativität. Nun, und Fehler wie dieser:
const user = getUser( userId ); greet( user.name ); // Uncaught TypeError: user is undefined Wenn Sie undefined -ähnliche Fehler in Ihrem Code satt haben, ist es an der Zeit, Ihrem Workflow einen Compiler hinzuzufügen. Werfen wir einen Blick darauf, was TypeScript ist und wie es uns ermöglicht, die Qualität unserer Software um mehrere Größenordnungen zu verbessern.
Was ist TypeScript
TypeScript ist eine JavaScript-basierte Programmiersprache, die mit dem Ziel entwickelt wurde, starke und statische Typisierung hinzuzufügen. TypeScript-Typen ermöglichen es uns, die Form unserer Objekte und Variablen zu beschreiben, was zu einem besser dokumentierten und robusteren Code führt. TypeScript selbst wird dafür verantwortlich sein, alles, was wir tun, zu validieren.
Wie entworfen, ist TypeScript eine Obermenge von JavaScript. Das bedeutet, dass jeder in reinem JavaScript geschriebene Code per Definition auch gültiges TypeScript ist. Das Gegenteil ist jedoch nicht der Fall: Wenn Sie TypeScript-spezifische Funktionen verwenden, ist der resultierende Code kein gültiges JavaScript, bis Sie ihn transpilieren.
So funktioniert TypeScript
Um zu verstehen, wie TypeScript funktioniert, verwenden wir seinen Playground , einen kleinen Editor, in dem wir TypeScript-Code schreiben und sehen können, was uns der Compiler darüber sagt.
Da es sich um eine Obermenge von JavaScript handelt, ist das Schreiben von TypeScript-Code extrem einfach. Grundsätzlich der folgende JavaScript-Code:
let user = "David"; let age = 34; let worksAtNelio = true; console.log( user, age, worksAtNelio );ist auch TypeScript-Code. Sie können es kopieren und in den TypeScript Playground einfügen und Sie werden sehen, dass es kompiliert wird. Also, was ist daran so besonders? Seine Typen natürlich. In JavaScript können Sie Folgendes tun:
let user = "David"; let age = 34; let worksAtNelio = true; user = { name: "Ruth" }; console.log( user, age, worksAtNelio );aber das wird einen Fehler in TypeScript auslösen. Probieren Sie es einfach im Playground aus und Sie werden den folgenden Fehler sehen:
Type '{ name: string; }' is not assignable to type 'string'.Worum geht es also?
TypeScript kann den Typ einer Variablen automatisch ableiten. Das bedeutet, dass wir ihr nicht explizit sagen müssen: „Hey, diese Variable ist ein String“ (oder eine Zahl, ein boolescher Wert oder was auch immer); Stattdessen sieht es sich den Wert an, der ihm zuerst gegeben wurde, und leitet daraus seinen Typ ab.

Als wir in unserem Beispiel die Variable user definiert haben, haben wir ihr die Textzeichenfolge "David" zugewiesen, sodass TypeScript weiß, dass user eine Zeichenfolge ist (und immer sein sollte). Das Problem ist, dass wir wenig später versuchen, den Typ unserer user zu ändern, indem wir ihr ein Objekt zuweisen, das eine einzige Eigenschaft ( name ) hat, deren Wert die Zeichenfolge "Ruth" ist. Offensichtlich ist dieses Objekt kein String , also beschwert sich TypeScript und teilt uns mit, dass die Zuweisung nicht durchgeführt werden kann.
Es gibt zwei mögliche Wege, dies zu beheben:
// Option 1 let user = "David"; user = "Ruth"; // OK. // Option 2 let user = { name: "David" }; user = { name: "Ruth" };Lassen Sie uns bei der Definition der Typen unserer Variablen explizit sein
Aber die Typinferenz ist nur da, um uns zu helfen. Wenn wir möchten, können wir TypeScript den Typ einer Variablen explizit mitteilen:
let user: string = "David"; let age: number = 34; let worksAtNelio: boolean = true; console.log( user, age, worksAtNelio );was genau das gleiche Ergebnis wie die von TypeScript abgeleiteten Typen liefert. Nun stellt sich die Frage: Wenn TypeScript Typen automatisch ableiten kann, warum brauchen wir diese Funktion?
Einerseits kann die explizite Angabe von Typen dazu dienen, unseren Code besser zu dokumentieren (was im nächsten Abschnitt noch deutlicher wird). Andererseits erlaubt es uns, die Beschränkungen des Typrückschlusssystems zu lösen. Ja, Sie haben richtig gelesen: Es gibt Fälle, in denen die Inferenz nicht sehr gut ist, und das Beste, was TypeScript tun kann, ist uns zu sagen: „Nun, ich weiß nicht, was diese Variable genau sein soll; Ich denke, es kann alles sein!“
Betrachten Sie das folgende Beispiel:
const getName = ( person ) => person.name; let david = { name: "David", age: 34 }; console.log( getName( david ) ); // Parameter 'person' implicitly has an 'any' type. In diesem Fall definieren wir eine getName Funktion, die einen Parameter empfängt und einen Wert zurückgibt. Beachten Sie, wie viele Dinge wir in einer so einfachen Funktion annehmen: Wir erwarten ein Objekt ( person ) mit mindestens einer Eigenschaft namens name . Aber wir haben keine wirkliche Garantie dafür, dass jeder, der diese Funktion aufruft, sie richtig verwendet. Aber selbst wenn sie es tun, wissen wir immer noch nicht, was der resultierende Typ dieser Funktion ist. Sicher, Sie könnten annehmen, dass ein Name eine Zeichenfolge ist, aber das wissen Sie nur, weil Sie ein Mensch sind und die Bedeutung dieses Wortes verstehen. Aber sehen Sie sich die folgenden Beispiele an:

getName( "Hola" ); // Error getName( {} ); // Returns undefined getName( { name: "David" } ); // Returns a string getName( { name: true } ); // Returns a booleanJedes Mal, wenn wir die Funktion aufrufen, erhalten wir ein anderes Ergebnis! Obwohl TypeScript uns den Rücken freihält, stoßen wir also immer noch auf klassische JavaScript-Probleme: Diese Funktion kann alles empfangen und alles zurückgeben.

Die Lösung, Sie haben es erraten, besteht darin, die Funktion explizit zu kommentieren.
Definieren Sie Ihre eigenen Typen
Aber bevor wir das tun, sehen wir uns ein weiteres zusätzliches TypeScript-Feature an: benutzerdefinierte Datentypen. Bisher haben fast alle unsere Beispiele grundlegende Typen wie string , number , boolean usw. verwendet, die meiner Meinung nach ziemlich einfach zu verstehen sind. Wir haben auch komplexere Datenstrukturen wie Objekte gesehen:
let david = { name: "David", age: 34 };aber wir haben dem von TypeScript abgeleiteten Typ nicht viel Aufmerksamkeit geschenkt, oder? Alles, was wir gesehen haben, ist ein Beispiel für eine ungültige Zuweisung aufgrund eines Tippfehlers:
let user = "David"; user = { name: "Ruth" }; // Type '{ name: string; }' is not assignable to type 'string'.was irgendwie andeutete, dass der Typ des Objekts „ {name:string;} “ war, was Sie lesen können als „dies ist ein Objekt mit einer Eigenschaft namens name vom Typ string .“ Wenn Objekttypen auf diese Weise definiert werden, sollte Folgendes gültiges TypeScript sein:
let david: { name: string, age: number } = { name: "David", age: 34 };und das ist es tatsächlich. Aber ich bin sicher, Sie werden zustimmen, dass es alles andere als bequem ist. Glücklicherweise können wir in TypeScript neue Typen erstellen.
Im Allgemeinen ist ein benutzerdefinierter Typ im Grunde ein regulärer TypeScript-Typ mit einem benutzerdefinierten Namen:
type Person = { name: string; age: number; }; let david: Person = { name: "David", age: 34 }; Cool was? Jetzt, da wir den Typ Person haben, können wir unsere getName Funktion einfach mit Anmerkungen versehen und den Typ unseres Eingabeparameters klar angeben:
const getName = ( person: Person ) => person.name; Und dieses einfache Update gibt TypeScript viele Informationen! Zum Beispiel kann es jetzt ableiten, dass der Ergebnistyp dieser Funktion ein String ist, weil es sicher weiß, dass das name eines Person -Objekts auch ein String ist:
let david: Person = { name: "David", age: 34 }; let davidName = getName( david ); davidName = 2; // Type 'number' is not assignable to type 'string'.Aber wie immer können Sie den Ergebnistyp explizit annotieren, wenn Sie möchten:
const getName = ( person: Person ): string => person.name;Mehr Zeug mit TypeScript-Typen…
Abschließend möchte ich Ihnen noch ein paar interessante Features vorstellen, von denen Sie profitieren können, wenn Sie Ihre eigenen Typen in TypeScript definieren.
TypeScript ist sehr anspruchsvoll, wenn es darum geht, Variablen Werte zuzuweisen. Wenn Sie den Typ einer bestimmten Variablen explizit definiert haben, können Sie nur Werte zuweisen, die genau diesem Typ entsprechen. Sehen wir es uns an mehreren Beispielen an:
type Person = { name: string; age: number; }; let david: Person = { name: "David", age: 34 }; // OK let ruth: Person = { name: "Ruth" }; // Property 'age' is missing in type '{ name: string; }' but required in type 'Person' let toni: Person = { name: "Toni", age: 35, gender: "M" }; // Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'. Object literal may only specify known properties, and 'gender' does not exist in type 'Person'. Wie Sie sehen können, akzeptiert eine Person -Variable nur Objekte, die vollständig dem Person -Typ entsprechen. Wenn einige Attribute fehlen ( ruth hat kein age ) oder mehr Attribute als die im Typ enthaltenen vorhanden sind ( toni hat ein gender ), beschwert sich TypeScript und löst einen Typkonfliktfehler aus.
Aber wenn wir über das Aufrufen von Funktionen sprechen, liegen die Dinge anders! Argumenttypen in einer Funktion sind keine exakte Anforderung, geben aber die minimale Schnittstelle an, der die Parameter entsprechen müssen. Ich weiß, ich weiß, das ist zu abstrakt. Schauen wir uns das folgende Beispiel an, das meiner Meinung nach die Dinge klarer machen wird:
type NamedObject = { name: string; }; const getName = ( obj: NamedObject ): string => obj.name; const ruth = { name: "Ruth" } getName( ruth ); // OK const david = { name: "David", age: 34 }; getName( david ); // OK const toni = { firstName: "Toni" }; getName( toni ); // Argument of type '{ firstName: string; }' is not assignable to parameter of type 'NamedObject'. Property 'name' is missing in type '{ firstName: string; }' but required in type 'NamedObject'. Wie Sie sehen können, haben wir die getName Funktion etwas generischer umdefiniert: Sie nimmt jetzt ein NamedObject- Objekt entgegen, d. h. ein Objekt, das ein Attribut namens name vom Typ string haben muss. Anhand dieser Definition sehen wir, wie ruth und david diese Anforderungen perfekt erfüllen (beide haben ein name -Attribut), aber toni nicht, da es nicht das erwartete Attribut name hat.
Fazit
TypeScript ist eine Programmiersprache, die JavaScript um statische Typdefinitionen erweitert. Dadurch können wir die Daten, mit denen wir arbeiten, viel präziser definieren und, was noch wichtiger ist, Fehler früher erkennen.
Die Kosten für die Integration von TypeScript in einen Entwicklungsstack sind relativ gering und können schrittweise erfolgen. Da der gesamte JavaScript-Code per Definition TypeScript ist, erfolgt der Wechsel von JavaScript zu TypeScript automatisch – Sie können Typen hinzufügen und Ihren Code Schritt für Schritt verschönern.
Wenn dir dieser Beitrag gefallen hat und du mehr erfahren möchtest, teile ihn bitte und lass es mich im Kommentarbereich unten wissen.
Vorgestelltes Bild von King's Church International auf Unsplash.
