ProgrammierungTypeScript Entwickler

Wie implementiert man die Überladung von Funktionen in TypeScript auf Signatur-Ebene und typisiert sie korrekt? Warum kann man nicht mehrere Funktionskörper verwenden, und was passiert mit den Typen der Parameter innerhalb des Funktionskörpers? Nennen Sie praktische Anwendungsfälle und die häufigsten Fehler.

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort.

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:

  • Mehrere überladene Signaturen hintereinander, eine Implementierung darunter.
  • Zum Arbeiten mit Parametern im Körper verwendet man entweder Union-Typen oder any/unknown.
  • Der Typ des Körpers ist breiter/allgemeiner als die Signaturen oben.

Knifflige Fragen.

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; }

Typische Fehler und Anti-Pattern

  • Fügt keine Implementierung nach den überladenden Signaturen hinzu — Kompilierung schlägt fehl.
  • Verwendet im Funktionskörper spezifische Eigenschaften ohne Typprüfung.
  • Kompliziert die Überladungen zu sehr, was zu unlesbarem Code führt.
  • Beschreibt nicht explizit die Rückgabetypen oder vergisst, die Signaturen bei Änderungen der Logik zu aktualisieren.

Beispiel aus dem Leben

Negativer Fall

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:

  • Idee, eine praktische API zu beschreiben

Nachteile:

  • Code kompiliert nicht, keine Variante kann verarbeitet werden

Positiver Fall

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:

  • Alle Varianten werden korrekt verarbeitet, Typen werden zur Kompilierungszeit abgeleitet

Nachteile:

  • Der Körper der Funktion erfordert manuelle Typkontrolle, man darf nicht vergessen, jede Variante zu überprüfen