TypeScript für Anfänger, Teil 5 Generics

Das zweite Tutorial in unserer TypeScript für Anfänger-Reihe konzentrierte sich auf grundlegende Datentypen, die in TypeScript verfügbar sind. Durch die Typüberprüfung in TypeScript können wir sicherstellen, dass den Variablen in unserem Code nur bestimmte Wertetypen zugewiesen werden können. Auf diese Weise können wir beim Schreiben von Code viele Fehler vermeiden, da uns die IDE mitteilen kann, wenn wir eine Operation an einem Typ ausführen, der nicht unterstützt wird. Dadurch ist die Typprüfung eine der besten Funktionen von TypeScript.

In diesem Tutorial konzentrieren wir uns auf ein anderes wichtiges Merkmal dieser Sprachgeneratoren. Mit Generics können Sie mit TypeScript Code schreiben, der auf verschiedene Datentypen angewendet werden kann, anstatt auf einen einzigen beschränkt zu sein. Sie werden im Detail erfahren, wie wichtig Generika sind und wie es besser ist, als nur die irgendein Datentyp in TypeScript verfügbar.

Die Notwendigkeit für Generika

Wenn Sie nicht mit Generika vertraut sind, fragen Sie sich vielleicht, warum wir sie überhaupt brauchen. In diesem Abschnitt werde ich diese Frage für Sie beantworten. Beginnen wir mit dem Schreiben einer Funktion, die ein zufälliges Element aus einem Zahlenfeld zurückgibt.

function randomIntElem (theArray: number []): number let randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex];  lassen Sie Positionen: Zahl [] = [103, 458, 472, 458]; let randomPosition: number = randomIntElem (Positionen);

Das randomElem Die Funktion, die wir gerade definiert haben, nimmt ein Array von Zahlen als einzigen Parameter. Der Rückgabetyp der Funktion wurde ebenfalls als Zahl angegeben. Wir benutzen die Math.random () Funktion, um eine Gleitkommazahl zwischen 0 und 1 zurückzugeben. Multiplizieren Sie diese mit der Länge eines gegebenen Arrays und rufen Sie auf Math.floor () auf dem Ergebnis gibt uns ein zufälliger Index. Sobald wir den Zufallsindex haben, geben wir das Element an diesem bestimmten Index zurück.

Einige Zeit später müssen Sie ein zufälliges String-Element aus einem String-Array abrufen. An dieser Stelle können Sie sich entscheiden, eine andere Funktion zu erstellen, die speziell auf Zeichenfolgen zielt.

function randomStrElem (theArray: string []): string let randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex];  Farben lassen: string [] = ['violett', 'indigo', 'blau', 'grün']; let randomColor: string = randomStrElem (Farben);

Was ist, wenn Sie ein zufälliges Element aus einem Array einer von Ihnen definierten Schnittstelle auswählen müssen? Das Erstellen einer neuen Funktion jedes Mal, wenn Sie ein zufälliges Element aus einem Array verschiedener Arten von Objekten erhalten möchten, ist nicht möglich.

Eine Lösung für dieses Problem besteht darin, den Typ der Array-Parameter festzulegen, die als Funktionen an die Funktionen übergeben werden irgendein[]. Auf diese Weise können Sie Ihre Funktion nur einmal schreiben und funktionieren mit einem Array aller Typen.

function randomElem (theArray: any []): any let randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex];  lassen Sie Positionen = [103, 458, 472, 458]; let randomPosition = randomElem (Positionen); lass Farben = ['violett', 'indigo', 'blau', 'grün']; let randomColor = randomElem (Farben);

Wie Sie sehen, können wir die obige Funktion verwenden, um sowohl zufällige Positionen als auch zufällige Farben zu erhalten. Ein Hauptproblem bei dieser Lösung besteht darin, dass Sie die Informationen über den zurückgegebenen Werttyp verlieren. 

Früher waren wir uns sicher randomPosition wäre eine Zahl und zufällige Farbe wäre eine Zeichenfolge. Dies hat uns geholfen, diese Werte entsprechend zu verwenden. Jetzt wissen wir nur, dass das zurückgegebene Element einen beliebigen Typ haben kann. Im obigen Code können wir den Typ von angeben zufällige Farbe ein ... zu sein Nummer und immer noch keine fehler erhalten.

// Dieser Code wird ohne Fehler kompiliert. Farben lassen: string [] = ['violett', 'indigo', 'blau', 'grün']; let randomColor: number = randomElem (Farben);

Eine bessere Lösung zur Vermeidung von Code-Duplizierung bei gleichzeitiger Beibehaltung der Typinformationen ist die Verwendung von Generics. Hier ist eine generische Funktion, die zufällige Elemente aus einem Array zurückgibt.

Funktion randomElem(theArray: T []): T let randomIndex = Math.floor (Math.random () * theArray.length); return theArray [randomIndex];  Farben lassen: string [] = ['violett', 'indigo', 'blau', 'grün']; let randomColor: string = randomElem (Farben);

Jetzt werde ich eine Fehlermeldung erhalten, wenn ich versuche, den Typ von zu ändern zufällige Farbe von Schnur zu Nummer. Dies beweist, dass die Verwendung von Generika viel sicherer ist als die Verwendung von irgendein tippen Sie in solchen Situationen.

Die Verwendung von Generics kann sehr einschränkend wirken

Im vorherigen Abschnitt wurde beschrieben, wie Sie Generika anstelle von verwenden können irgendein type, um eine einzige Funktion zu schreiben und die Vorteile der Typprüfung nicht zu beeinträchtigen. Ein Problem mit der generischen Funktion, die wir im vorherigen Abschnitt geschrieben haben, besteht darin, dass wir mit TypeScript nicht viele Operationen an den an sie übergebenen Variablen ausführen können. 

Dies liegt daran, dass TypeScript keine Annahmen über den Variablentyp treffen kann, der zuvor an unsere generische Funktion übergeben wird. Daher kann unsere generische Funktion nur die Operationen verwenden, die für alle Datentypen gelten. Das folgende Beispiel soll dieses Konzept verdeutlichen.

function removeChar (theString: string, theChar: string): string let theRegex = new RegExp (theChar, "gi"); return theString.replace (theRegex, ");

Die obige Funktion entfernt alle Vorkommen des angegebenen Zeichens aus der angegebenen Zeichenfolge. Möglicherweise möchten Sie eine generische Version dieser Funktion erstellen, damit Sie auch bestimmte Ziffern aus einer bestimmten Zahl sowie Zeichen aus einer Zeichenfolge entfernen können. Hier ist die entsprechende generische Funktion.

Funktion removeIt(theInput: T, theIt: string): T let theRegex = new RegExp (theIt, "gi"); return theInput.replace (theRegex, ");

Das removeChar Funktion hat keinen Fehler angezeigt. Wenn Sie jedoch verwenden ersetzen Innerhalb entfernen Sie es,TypeScript sagt Ihnen das ersetzen existiert nicht für Typ 'T'. Dies liegt daran, dass TypeScript dies nicht mehr annehmen kann die Eingabe wird eine Zeichenfolge sein.

Diese Einschränkung bei der Verwendung verschiedener Methoden in einer generischen Funktion könnte dazu führen, dass das Konzept der Generics nicht viel nützt. Es gibt nicht wirklich viel, was Sie mit einer Handvoll Methoden tun können, die auf alle Datentypen anwendbar sein müssen, damit Sie sie innerhalb einer generischen Funktion verwenden können.

Eine wichtige Sache, die Sie zu diesem Zeitpunkt beachten sollten, ist, dass Sie im Allgemeinen keine Funktionen erstellen müssen, die mit allen Arten von Datentypen verwendet werden. Es ist üblicher, eine Funktion zu erstellen, die mit einem bestimmten Satz oder Bereich von Datentypen verwendet wird. Diese Einschränkung für Datentypen macht generische Funktionen viel nützlicher.

Erstellen Sie generische Funktionen mit Einschränkungen

Das generische entfernen Sie es Funktion aus dem vorherigen Abschnitt zeigte einen Fehler, weil die ersetzen Diese Methode ist für Strings gedacht, während die an sie übergebenen Parameter einen beliebigen Datentyp haben können. 

Du kannst den ... benutzen erweitert Schlüsselwort, um die Datentypen einzuschränken, die in TypeScript an eine generische Funktion übergeben werden. jedoch, erweitert ist nur auf Schnittstellen und Klassen beschränkt. Dies bedeutet, dass die meisten generischen Funktionen, die Sie erstellen, über Parameter verfügen, die eine Basisschnittstelle oder -klasse erweitern. 

Hier ist eine generische Funktion, die den Namen von Personen, Familienmitgliedern oder Prominenten druckt, die an sie übergeben wurden.

interface People Name: String Interface Familie Name: String, Alter: Nummer, Beziehung: String Interface Celebrity erweitert die Funktion People profession: string printName(theInput: T): void console.log ('Mein Name ist $ theInput.name');  Lassen Sie Serena: Celebrity = Name: 'Serena Williams', Beruf: 'Tennis Player' printName (Serena);

Im obigen Beispiel haben wir drei Schnittstellen definiert, und jede hat eine Name Eigentum. Das generische printName Funktion, die wir erstellt haben, akzeptiert jedes Objekt, das erweitert wird Menschen. Mit anderen Worten, Sie können entweder ein Familienobjekt oder ein Prominentenobjekt an diese Funktion übergeben, und der Name wird ohne Beschwerden gedruckt. Sie können viele weitere Schnittstellen definieren, sofern sie über eine Name Eigenschaft können Sie die printName Funktionieren ohne Probleme.

Dies war ein sehr einfaches Beispiel, aber Sie können nützlichere generische Funktionen erstellen, wenn Sie mit dem gesamten Prozess vertraut sind. Sie können beispielsweise eine generische Funktion erstellen, die den Gesamtwert der verschiedenen in einem bestimmten Monat verkauften Artikel berechnet, sofern jeder Artikel über einen Wert verfügt Preis Eigenschaft, um den Preis zu speichern und a verkauft Eigenschaft, die die Anzahl der verkauften Artikel speichert. Mit Generics können Sie dieselbe Funktion verwenden, solange die Elemente dieselbe Schnittstelle oder Klasse erweitern.

Abschließende Gedanken

In diesem Tutorial habe ich versucht, die Grundlagen von Generics in TypeScript für Anfänger zu behandeln. Wir begannen den Artikel mit der Erörterung der Notwendigkeit von Generika. Danach haben wir gelernt, wie Generics richtig eingesetzt werden können, um Code-Duplizierung zu vermeiden, ohne die Typprüfung zu beeinträchtigen. Wenn Sie die hier behandelten Grundlagen verstanden haben, können Sie mehr über Generika in der offiziellen Dokumentation lesen.

Wenn Sie Fragen zu diesem Tutorial haben, beantworte ich diese gerne in den Kommentaren.