TypeScript - Generische Einschränkungen: Die Macht flexibler Typen entfesseln
Hallo da draußen, zukünftige TypeScript-Zauberer! Heute begeben wir uns auf eine aufregende Reise in die Welt der Generischen Einschränkungen. Keine Sorge, wenn du neu im Programmieren bist – ich werde dein freundlicher Guide sein, und wir werden dieses Thema Schritt für Schritt angehen. Am Ende dieses Tutorials wirst du Generics wie ein Profi einschränken können!
Was sind Generische Einschränkungen?
Bevor wir ins Detail gehen, lassen Sie uns mit einer einfachen Analogie beginnen. Stell dir vor, du hast eine magische Box, die alle Arten von Gegenständen aufnehmen kann. Das ist im Wesentlichen, was ein Generic in TypeScript ist – ein flexibler Behälter für verschiedene Typen. Was wäre, wenn wir einige Regeln darauf legen möchten, was in diese Box kann? Genau hier kommen die generischen Einschränkungen ins Spiel!
Generische Einschränkungen erlauben es uns, die Typen zu beschränken, die mit unseren Generics verwendet werden können. Es ist wie das Anbringen einer Etikette an unserer magischen Box, die sagt: "Nur Objekte mit einer 'length'-Eigenschaft erlaubt!"
Problembeispiele: Warum brauchen wir Generische Einschränkungen?
Schauen wir uns einige Szenarien an, in denen generische Einschränkungen den Tag retten können:
Beispiel 1: Die geheimnisvolle 'length'-Eigenschaft
function getLength<T>(item: T): number {
return item.length; // Fehler: Eigenschaft 'length' existiert nicht auf Typ 'T'
}
Ups! TypeScript gibt uns einen Fehler. Warum? Weil nicht alle Typen eine length
-Eigenschaft haben. Was wäre, wenn wir dieser Funktion eine Zahl übergeben? Zahlen haben keine Länge!
Beispiel 2: Der verwirrende Vergleich
function compareValues<T>(value1: T, value2: T): boolean {
return value1 > value2; // Fehler: Operator '>' kann nicht auf Typen 'T' und 'T' angewendet werden
}
Noch ein Fehler! TypeScript weiß nicht, ob T
mit >
verglichen werden kann. Was wäre, wenn wir Zeichenfolgen übergeben? Oder komplexe Objekte?
Diese Beispiele zeigen uns, warum wir generische Einschränkungen brauchen. Sie helfen uns, präziser und fehlerfreier Code zu schreiben.
Wie Generische Einschränkungen in TypeScript funktionieren
Nun sehen wir, wie wir generische Einschränkungen verwenden können, um unsere Probleme zu lösen:
Das magische 'extends'- Schlüsselwort
Um eine Einschränkung hinzuzufügen, verwenden wir das extends
-Schlüsselwort. Es ist so, als würde TypeScript sagen: "Hey, dieser Typ muss mindestens diese Eigenschaften oder Fähigkeiten haben!"
Lassen Sie uns unsere getLength
-Funktion beheben:
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(item: T): number {
return item.length; // Kein Fehler mehr!
}
Lassen Sie uns das herunterbrechen:
- Wir definieren eine Schnittstelle
Lengthwise
, die einelength
-Eigenschaft hat. - Wir verwenden
<T extends Lengthwise>
, um zu sagen "T muss mindestens das haben, was Lengthwise hat". - Jetzt weiß TypeScript, dass was auch immer
T
ist, es definitiv einelength
-Eigenschaft haben wird!
Lassen Sie es ausprobieren:
console.log(getLength("Hello")); // Funktioniert! Zeichenfolgen haben Länge
console.log(getLength([1, 2, 3])); // Funktioniert! Arrays haben Länge
console.log(getLength(123)); // Fehler! Zahlen haben keine Länge
Ist das nicht toll? Wir haben erfolgreich unser Generic eingeschränkt!
Typenparameter in Generischen Einschränkungen verwenden
Manchmal möchten wir einen Typenparameter basierend auf einem anderen einschränken. Es ist, als würde man sagen: "Diese Box kann nur Gegenstände aufnehmen, die kompatibel sind mit dem, was bereits drin ist."
Schauen wir uns ein Beispiel an:
function copyProperties<T extends U, U>(target: T, source: U): T {
for (let id in source) {
target[id] = source[id];
}
return target;
}
Was passiert hier?
- Wir haben zwei Typenparameter:
T
undU
. -
T extends U
bedeutet, dassT
mindestens alles ist, wasU
ist, aber es kann mehr sein. - Dies ermöglicht es uns, Eigenschaften von
source
nachtarget
zu kopieren, in dem Wissen, dasstarget
alle Eigenschaften hat, diesource
hat.
Lassen Sie es in Aktion sehen:
interface Person {
name: string;
}
interface Employee extends Person {
employeeId: number;
}
let person: Person = { name: "Alice" };
let employee: Employee = { name: "Bob", employeeId: 123 };
copyProperties(employee, person); // Funktioniert!
copyProperties(person, employee); // Fehler! Person hat keine employeeId
Praktische Anwendungen und Best Practices
Nun, da wir verstehen, wie generische Einschränkungen funktionieren, schauen wir uns einige realweltliche Anwendungen und Best Practices an:
- Einschränkung auf Objekttypen: Oftentimes, you'll want to ensure you're working with objects:
function cloneObject<T extends object>(obj: T): T {
return { ...obj };
}
- Einschränkung auf Funktionstypen: You can ensure a type is callable:
function invokeFunction<T extends Function>(func: T): void {
func();
}
- Einschränkung auf spezifische Eigenschaften: Ensure objects have specific properties:
function getFullName<T extends { firstName: string; lastName: string }>(obj: T): string {
return `${obj.firstName} ${obj.lastName}`;
}
-
Mehrere Einschränkungen: You can apply multiple constraints using the
&
operator:
function processData<T extends number & { toFixed: Function }>(data: T): string {
return data.toFixed(2);
}
Hier ist eine Tabelle, die diese Methoden zusammenfasst:
Methode | Beschreibung | Beispiel |
---|---|---|
Objekt-Einschränkung | Stellt sicher, dass der Typ ein Objekt ist | <T extends object> |
Funktionseinschränkung | Stellt sicher, dass der Typ aufrufbar ist | <T extends Function> |
Eigenschaftseinschränkung | Stellt sicher, dass der Typ spezifische Eigenschaften hat | <T extends { prop: Type }> |
Mehrfache Einschränkungen | Kombiniert mehrere Einschränkungen | <T extends TypeA & TypeB> |
Schlussfolgerung: Die Macht der Einschränkungen nutzen
Glückwunsch! Du hast ein mächtiges Werkzeug in deinem TypeScript-Werkzeugkasten entsperrt. Generische Einschränkungen erlauben es uns, flexiblen, aber typensicheren Code zu schreiben und das Beste aus beiden Welten zu haben.
Denk daran, der Schlüssel zum Beherrschen von generischen Einschränkungen ist die Übung. Versuche, einige deiner bestehenden Codes in Generics und Einschränkungen umzuwandeln. Du wirst überrascht sein, wie sauberer und robuster dein Code wird!
Als wir uns verabschieden, hier ist ein kleiner Programmierwitz für dich: Warum ist der TypeScript-Entwickler pleite gegangen? Weil er zu viele generische Einschränkungen verwendet und keine Art von Zahlung akzeptieren konnte! ?
Weiter codieren, weiter lernen und vor allem: Viel Spaß mit TypeScript!
Credits: Image by storyset