TypeScript - Generics: A Beginner's Guide

Hallo da, zukünftiger Codingsuperstar! Heute machen wir uns auf eine aufregende Reise in die Welt der TypeScript-Generics. Mach dir keine Sorgen, wenn du neu im Programmieren bist – ich werde dein freundlicher Guide sein, und wir gehen das Schritt für Schritt durch. Bis zum Ende dieses Tutorials wirst du Generics wie ein Profi einsetzen können!

TypeScript - Generics

Was sind Generics und warum sollten wir uns darum kümmern?

Bevor wir uns den Details widmen, beginnen wir mit einer einfachen Analogie. Stell dir vor, du hast eine magische Box, die jeden Gegenstand aufnehmen kann. Manchmal legst du ein Buch hinein, manchmal ein Spielzeug oder sogar ein Sandwich. Das ist im Grunde genommen, was Generics in TypeScript sind – sie erlauben es uns, flexiblen, wiederverwendbaren Code zu erstellen, der mit verschiedenen Typen funktionieren kann.

Problembeispiele

Sehen wir uns einige Szenarien an, in denen Generics den Tag retten können:

  1. Du möchtest eine Funktion erstellen, die jedes Array-Typ (Zahlen, Strings, Objekte) umkehren kann.
  2. Du benötigst eine Klasse, die jede Art von Daten speichern und abrufen kann.
  3. Du baust eine Utility-Funktion, die mit verschiedenen Datentypen funktionieren sollte.

Ohne Generics müsstest du separate Funktionen oder Klassen für jeden Datentyp schreiben. Das ist viel Wiederholung, und wie jeder gute Programmierer weiß, ist Wiederholung der Feind sauberen Codes!

TypeScript Generics zur Rettung!

Nun, rollen wir die Ärmel hoch und sehen wir, wie Generics in der Praxis funktionieren.

Grundlegende Generische Funktion

Hier ist eine einfache generische Funktion, die mit jedem Typ arbeiten kann:

function identity<T>(arg: T): T {
return arg;
}

Lassen wir das auseinanderfallen:

  • <T> ist unser Typenparameter. Es ist wie ein Platzhalter für den Typ, den wir verwenden werden.
  • (arg: T) bedeutet, unsere Funktion nimmt ein Argument des Typs T an.
  • : T nach den Klammern bedeutet, unsere Funktion wird einen Wert des Typs T zurückgeben.

Wir können diese Funktion如此 verwenden:

let output1 = identity<string>("Hello, Generics!");
let output2 = identity<number>(42);

console.log(output1); // "Hello, Generics!"
console.log(output2); // 42

Cool, oder? Die gleiche Funktion funktioniert mit verschiedenen Typen!

Generisches Interface

Wir können auch Generics mit Schnittstellen verwenden. Hier ist ein Beispiel:

interface GenericBox<T> {
contents: T;
}

let stringBox: GenericBox<string> = { contents: "A secret message" };
let numberBox: GenericBox<number> = { contents: 123 };

console.log(stringBox.contents); // "A secret message"
console.log(numberBox.contents); // 123

Unser GenericBox kann jeden Inhaltstyp aufnehmen. Es ist wie diese magische Box, die wir earlier darüber gesprochen haben!

Generische Klassen

Lassen Sie uns eine generische Klasse erstellen, die als einfacher DatenSpeicher dienen kann:

class DataStore<T> {
private data: T[] = [];

addItem(item: T): void {
this.data.push(item);
}

getItems(): T[] {
return this.data;
}
}

let stringStore = new DataStore<string>();
stringStore.addItem("Hello");
stringStore.addItem("World");
console.log(stringStore.getItems()); // ["Hello", "World"]

let numberStore = new DataStore<number>();
numberStore.addItem(1);
numberStore.addItem(2);
console.log(numberStore.getItems()); // [1, 2]

Diese DataStore-Klasse kann Daten jeden Typs speichern und abrufen. quite nützlich, oder?

Generische Einschränkungen

Manchmal möchten wir die Typen einschränken, die mit unseren Generics verwendet werden können. Wir können das mit Einschränkungen tun:

interface Lengthy {
length: number;
}

function logLength<T extends Lengthy>(arg: T): void {
console.log(arg.length);
}

logLength("Hello"); // 5
logLength([1, 2, 3]); // 3
logLength({ length: 10 }); // 10
// logLength(123); // Fehler: Number hat keine length-Eigenschaft

Hier kann unsere logLength-Funktion nur mit Typen arbeiten, die eine length-Eigenschaft haben.

Vorteile von Generics

Jetzt, da wir Generics in Aktion gesehen haben, lassen Sie uns ihre Vorteile zusammenfassen:

  1. Code-Wiederverwendbarkeit: Einmal schreiben, mit vielen Typen verwenden.
  2. Typensicherheit: Typbezogene Fehler bereits zur Compile-Zeit fangen.
  3. Flexibilität: Erstellen von Komponenten, die mit einer Vielzahl von Datentypen funktionieren können.
  4. Klarheit: Machen Sie die Beziehungen zwischen Eingaben und Ausgaben klar.

Tabelle der generischen Methoden

Hier ist eine praktische Tabelle einiger häufiger generischer Methoden, die du begegnen könntest:

Methode Beschreibung Beispiel
Array.map<U>() Transformiert Array-Elemente [1, 2, 3].map<string>(n => n.toString())
Promise.all<T>() Wartet, bis alle Promises gelöst sind Promise.all<number>([Promise.resolve(1), Promise.resolve(2)])
Object.keys<T>() Holt die Schlüssel eines Objekts als Array Object.keys<{name: string}>({name: "Alice"})
JSON.parse<T>() Parst einen JSON-String in ein Objekt JSON.parse<{age: number}>('{"age": 30}')

Schlussfolgerung

Glückwunsch! Du hast gerade deine ersten Schritte in die wundersame Welt der TypeScript-Generics unternommen. Denke daran, dass Generics wie jedes mächtige Werkzeug am Anfang vielleicht ein bisschen tricky erscheinen, aber mit Übung werden sie zur zweiten Natur.

Wenn du deine编码-Reise fortführst, wirst du feststellen, dass Generics wie ein Schweizer Taschenmesser in deinem TypeScript-Werkzeugkasten sind – vielseitig, mächtig und unglaublich nützlich. Also, weiter codieren, junger Padawan, und möge die Generics mit dir sein!

Frohes Coden und bis zum nächsten Mal, weiter erkunden und lernen!

Credits: Image by storyset