Die Überladung von Funktionen ermöglicht es, eine Funktion mit verschiedenen Varianten von Eingabeparametern und Rückgabewerten zu erstellen. In anderen Sprachen wie C# oder Java kann man mehrere Funktionen mit demselben Namen, aber unterschiedlichen Typen oder Mengen an Argumenten beschreiben. TypeScript ahmt diesen Mechanismus durch Überlastung von Signaturen auf Typeneben nach, jedoch hat der Funktionskörper immer nur eine Implementierung.
Das Problem dabei ist, dass JavaScript keine native Unterstützung für die Überladung nach Typ oder Anzahl der Parameter hat. Mit dem Erscheinen von TypeScript wird die Überladung durch die Deklaration mehrerer Funktionssignaturen hintereinander und einer einzigen Implementierung emuliert, innerhalb derer man manuell unterscheidet, mit welchem Typ gerade gearbeitet wird.
Das Problem tritt auf, wenn man nicht auf die Übereinstimmung mit den deklarierten Signaturen achtet: Innerhalb des Funktionskörpers weist TypeScript den allgemeinsten Typ (Vereinigung aller Parameter) zu, und der Programmierer muss Prüfungen und Typwachen durchführen.
Lösung: Überladungen strikt in expliziten Signaturen typisieren, gut mit Union-Types und Typwachen arbeiten, das Verhalten klar dokumentieren.
Codebeispiel:
function format(value: string): string; function format(value: number, locale: string): string; function format(value: any, locale?: string): string { if (typeof value === 'number') { return value.toLocaleString(locale); } return value.trim(); } format(' hello '); // 'hello' format(123456, 'ru-RU'); // '123 456'
Wichtige Merkmale:
Kann man mehrere Funktionen mit demselben Namen und unterschiedlichen Körpern wie in C# deklarieren?
Nein. In TypeScript (und JavaScript) existiert tatsächlich nur eine Funktion mit diesem Namen. Überladungen funktionieren nur auf Typ-Ebene für den Compiler, aber es gibt nur einen Funktionskörper.
Was passiert, wenn man die Signatur mit den allgemeinsten Parametern nach den überladenden Signaturen nicht implementiert?
TypeScript gibt einen Kompilierungsfehler aus. Es muss immer eine Implementierungsfunktion geben, deren Parameter alle möglichen Varianten der Überladungen abdecken.
function foo(a: string): string; function foo(a: number): number; // kein Körper — Fehler
Kann ich innerhalb des Körpers spezifische Eigenschaften für eine bestimmte Signatur verwenden?
Nein, nur nach einer Typprüfung (Type Guard) oder Typumwandlung. Andernfalls erlaubt TypeScript nicht, diese Eigenschaften direkt zu verwenden, da nicht bekannt ist, nach welcher Signatur der Aufruf erfolgt.
function bar(x: string): number; function bar(x: number): number; function bar(x: string | number): number { if (typeof x === 'string') return x.length; return x * 2; }
Die universelle Implementierungs-Signatur wurde vergessen hinzuzufügen:
function sum(a: string, b: string): string; function sum(a: number, b: number): number; // keine Implementierung — Compiler meckert
Vorteile:
Nachteile:
Die Überladung wird gemäß dem Standard implementiert:
function sum(a: string, b: string): string; function sum(a: number, b: number): number; function sum(a: any, b: any): any { return typeof a === 'string' && typeof b === 'string' ? a + b : a + b; }
Vorteile:
Nachteile: