Zum Inhalt springen
aviral gupta

// B4.3 · ca. 30 Min. · Einstieg

Funktionsüberladungen

Nach dieser Lektion schreiben Sie Funktionen, die sich auf mehrere Arten aufrufen lassen, lesen die Fehler, die tsc dafür meldet, und erkennen, wann ein Union-Parameter einfacher ist.

Lektion 3 von 5 in B4 Mehr zu Funktionen

Danach können Sie

  • Overload-Signaturen schreiben und eine Implementierungssignatur, die zu ihnen kompatibel ist
  • Fehler überladener Aufrufe lesen, im Wissen, dass Aufrufer nur die Overload-Signaturen sehen
  • Einen Union-Parameter Overloads vorziehen, wenn der Rückgabetyp nicht vom Argument abhängt
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen aus JavaScript: len wird mit drei Arten von Werten aufgerufen. Was gibt das aus?

    function len(x) {
      return x.length;
    }
    
    console.log(len("hello"), len([1, 2]), len(42));
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie es vorher, bevor Sie weiterlesen. makeDate hat zwei Overload-Signaturen, dann eine Implementierung mit zwei optionalen Parametern. Was meldet tsc für die letzte Zeile?

    function makeDate(timestamp: number): Date;
    function makeDate(m: number, d: number, y: number): Date;
    function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
      if (d !== undefined && y !== undefined) {
        return new Date(y, mOrTimestamp, d);
      } else {
        return new Date(mOrTimestamp);
      }
    }
    const d1 = makeDate(12345678);
    const d2 = makeDate(5, 5, 5);
    const d3 = makeDate(1, 3);
  3. Üben · Aufgabe 3 von 7

    Ergänzen Sie den Parametertyp der Implementierung, sodass sie zu beiden Overloads kompatibel ist und das Programm 499 [ 150, 25 ] ausgibt.

    function toCents(euros: number): number;
    function toCents(euros: number[]): number[];
    function toCents(euros: ____): number | number[] {
      if (Array.isArray(euros)) return euros.map((e) => Math.round(e * 100));
      return Math.round(euros * 100);
    }
    
    console.log(toCents(4.99), toCents([1.5, 0.25]));
    function toCents(euros: ): number | number[] {
  4. Üben · Aufgabe 4 von 7

    pad hat in der Implementierung Defaults für width und fill. Welche Zeile lehnt tsc ab?

    function pad(text: string): string;
    function pad(text: string, width: number, fill: string): string;
    function pad(text: string, width = 8, fill = " "): string {
      return text.padStart(width, fill);
    }
    
    pad("7");
    pad("7", 3);
    pad("7", 3, "0");
  5. Üben · Aufgabe 5 von 7

    Der zweite Overload verspricht einen boolean. Was meldet tsc?

    function fn(x: string): string;
    function fn(x: number): boolean;
    function fn(x: string | number) {
      return "oops";
    }
  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Die Implementierung behandelt sogar einen fehlenden input. Was meldet tsc für diese Datei?

    function greet(name: string): string;
    function greet(names: string[]): string;
    function greet(input?: string | string[]): string {
      if (input === undefined) return "Hello, nobody";
      return "Hello, " + (Array.isArray(input) ? input.join(" and ") : input);
    }
    
    console.log(greet(["Ada", "Grace"]));
    console.log(greet());
  7. Anwenden · Aufgabe 7 von 7

    Mini-Aufgabe. Schreiben Sie euro, das Cent in Text wie 4.50 EUR umwandelt. Mit einer Zahl aufgerufen, gibt es einen string zurück, mit einem Array von Zahlen ein string[]. Verwenden Sie zwei Overload-Signaturen und eine Implementierung. Schreiben Sie dann size, das die Länge eines Strings oder eines string[] zurückgibt: eine Signatur mit Union-Parameter, denn der Rückgabetyp ist in beiden Fällen gleich. Speichern Sie euro(450) in einer const vom Typ string und euro([199, 2500]) in einer vom Typ string[]. Prüfen Sie es im Editor oder mit npx tsc und node main.ts.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Datumsangaben, Cent und Längen

makeDate wird mit einem Zeitstempel oder mit Jahr, Monat und Tag aufgerufen: Die Argumentzahlen unterscheiden sich, also braucht es Overloads. toCents gibt für eine Zahl eine Zahl zurück und für ein Array ein Array: Der Rückgabetyp hängt vom Argument ab, also hat es ebenfalls Overloads. len gibt in jedem Fall eine Zahl zurück, also genügt ein Union-Parameter. Führen Sie npx tsc aus, dann node main.ts. Ergänzen Sie danach die Zeile makeDate(2026, 10); und führen Sie tsc erneut aus.

main.ts

// One function, two ways to call it: overload signatures, then one implementation.
function makeDate(timestamp: number): Date;
function makeDate(year: number, month: number, day: number): Date;
function makeDate(yearOrTimestamp: number, month?: number, day?: number): Date {
  if (month !== undefined && day !== undefined) {
    return new Date(Date.UTC(yearOrTimestamp, month - 1, day));
  }
  return new Date(yearOrTimestamp);
}

// The return type follows the argument: a number gives a number, an array an array.
function toCents(euros: number): number;
function toCents(euros: number[]): number[];
function toCents(euros: number | number[]): number | number[] {
  if (Array.isArray(euros)) return euros.map((e) => Math.round(e * 100));
  return Math.round(euros * 100);
}

// The same return type either way: a union parameter is simpler.
function len(x: string | number[]): number {
  return x.length;
}

const day = (date: Date) => date.toISOString().slice(0, 10);
console.log(day(makeDate(0)), day(makeDate(2026, 10, 4)));

const one = toCents(4.99); // number
const many = toCents([1.5, 0.25]); // number[]
console.log(one + 1, many.join(" + "));

const input = Math.random() > 0.5 ? "hello" : [1, 2, 3, 4, 5];
console.log(len(input));

Ausführen mit

npx tsc
node main.ts

Ausgabe

1970-01-01 2026-10-04
500 150 + 25
5
  • one ist eine Zahl, also besteht one + 1 die Typprüfung; nur mit der Implementierungssignatur wäre es number | number[].
  • makeDate(2026, 10) ist error TS2575: Kein Overload nimmt zwei Argumente.
  • input ist "hello" oder ein Array aus fünf Zahlen, also gibt len in jedem Fall 5 aus, und nur ein Union-Parameter nimmt es an.
  • Date.UTC zählt Monate ab 0, daher month - 1 in der Implementierung.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Eine Dauer mit zwei Overloads

duration(90) soll 1:30 ergeben und duration(2, 5), mit Minuten und Sekunden, 2:05. Die beiden Overloads sind da, und tsc akzeptiert die Datei: Eine Implementierung mit weniger Parametern gilt als kompatibel. Aber sie ignoriert das zweite Argument, also ergibt duration(2, 5) 0:02. Ändern Sie die Implementierungssignatur so, dass sie beide Argumente bekommt, das zweite optional, und berechnen Sie die Gesamtsekunden für beide Arten des Aufrufs. Lassen Sie die Overloads, wie sie sind.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Die Implementierung muss annehmen, was beide Overloads übergeben: eine Zahl oder zwei. Machen Sie den zweiten Parameter optional.

  2. Hinweis 2

    Benennen Sie die Parameter nach dem, was sie enthalten können, zum Beispiel (first: number, second?: number).

  3. Hinweis 3

    const total = second === undefined ? first : first * 60 + second; dann berechnen Sie Minuten und Sekunden aus total wie zuvor.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function duration(seconds: number): string;
export function duration(minutes: number, seconds: number): string;
export function duration(first: number, second?: number): string {
  const total = second === undefined ? first : first * 60 + second;
  const minutes = Math.floor(total / 60);
  return minutes + ":" + String(total % 60).padStart(2, "0");
}
Auf dem eigenen Computer ausführen

Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.ts

export function duration(seconds: number): string;
export function duration(minutes: number, seconds: number): string;
export function duration(total: number): string {
  const minutes = Math.floor(total / 60);
  return minutes + ":" + String(total % 60).padStart(2, "0");
}

main.test.ts

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {duration} from './main.ts';

test('duration(90) ist 1:30', () => {
  assert.equal(duration(90), '1:30', `duration(90) ergab ${JSON.stringify(duration(90))}`);
});

test('duration(5) ist 0:05', () => {
  assert.equal(duration(5), '0:05', `duration(5) ergab ${JSON.stringify(duration(5))}`);
});

test('duration(2, 5) ist 2:05', () => {
  assert.equal(duration(2, 5), '2:05', `duration(2, 5) ergab ${JSON.stringify(duration(2, 5))}`);
});

test('duration(1, 75) rechnet die Sekunden um: 2:15', () => {
  assert.equal(duration(1, 75), '2:15', `duration(1, 75) ergab ${JSON.stringify(duration(1, 75))}`);
});

package.json

{
  "type": "module"
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "lib": [
      "esnext",
      "dom"
    ],
    "types": [],
    "strict": true,
    "noEmit": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "**/*.test.ts"
  ]
}

npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.

Programm ausführen:

npx tsc
node main.ts

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

npx tsc
node --test
learnrun.js herunterladen

Übung 2 von 2

Von Overloads zur Union

wordCount zählt die Wörter in einem String oder in einem Array von Zeilen. countAll reicht einen string | string[] daran weiter, und tsc meldet error TS2769: No overload matches this call. Beide Overloads nehmen ein Argument und geben eine Zahl zurück, also ersetzen Sie sie durch eine einzige Signatur: Behalten Sie die Implementierung mit ihrem Union-Parameter und löschen Sie die beiden Overload-Zeilen. Lassen Sie countAll, wie es ist.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den TypeScript-Compiler herunter (bis zu 2.1 MB) und speichert ihn im Cache. Ihr Code bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    TypeScript löst einen Aufruf zu einem Overload auf, und input in countAll kann beides sein.

  2. Hinweis 2

    Die Implementierungssignatur hat den Union-Parameter schon. Sobald die Overloads weg sind, ist sie die, die Aufrufer sehen.

  3. Hinweis 3

    Löschen Sie die Zeilen export function wordCount(text: string): number; und export function wordCount(lines: string[]): number;.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

export function wordCount(input: string | string[]): number {
  const text = Array.isArray(input) ? input.join(" ") : input;
  return text.split(" ").filter((word) => word !== "").length;
}

export function countAll(input: string | string[]): number {
  return wordCount(input);
}
Auf dem eigenen Computer ausführen

Installieren Sie TypeScript 7.0 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.ts

export function wordCount(text: string): number;
export function wordCount(lines: string[]): number;
export function wordCount(input: string | string[]): number {
  const text = Array.isArray(input) ? input.join(" ") : input;
  return text.split(" ").filter((word) => word !== "").length;
}

export function countAll(input: string | string[]): number {
  return wordCount(input);
}

main.test.ts

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {wordCount, countAll} from './main.ts';

test('wordCount zählt die Wörter in einem String', () => {
  assert.equal(wordCount('to be or not'), 4, `wordCount('to be or not') ergab ${wordCount('to be or not')}`);
});

test('wordCount zählt die Wörter in allen Zeilen', () => {
  assert.equal(wordCount(['a b', 'c']), 3, `wordCount(['a b', 'c']) ergab ${wordCount(['a b', 'c'])}`);
});

test('countAll funktioniert für einen String und für Zeilen', () => {
  assert.equal(countAll('one two'), 2, `countAll('one two') ergab ${countAll('one two')}`);
  assert.equal(countAll(['one', 'two three']), 3, `countAll(['one', 'two three']) ergab ${countAll(['one', 'two three'])}`);
});

test('ein leerer String hat keine Wörter', () => {
  assert.equal(wordCount(''), 0, `wordCount('') ergab ${wordCount('')}`);
});

package.json

{
  "type": "module"
}

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "nodenext",
    "lib": [
      "esnext",
      "dom"
    ],
    "types": [],
    "strict": true,
    "noEmit": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "allowImportingTsExtensions": true
  },
  "include": [
    "**/*.ts"
  ],
  "exclude": [
    "**/*.test.ts"
  ]
}

npx tsc braucht TypeScript im Ordner: Führen Sie dort einmal npm install --save-dev typescript aus. tsc prüft die Typen; Node.js führt main.ts aus, indem es sie entfernt.

Programm ausführen:

npx tsc
node main.ts

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

npx tsc
node --test
learnrun.js herunterladen

Häufige Fehler

Aufruf mit der Parameterliste der Implementierung

function pad(text: string): string;
function pad(text: string, width: number, fill: string): string;
function pad(text: string, width = 8, fill = " "): string {
  return text.padStart(width, fill);
}

console.log(pad("7", 3));

Was tsc oder Node.js ausgibt

main.ts(7,13): error TS2575: No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.

Warum, und die Lösung

Die Defaults gehören zur Implementierungssignatur, und die sehen Aufrufer nicht: Nur die Overloads zählen. Ergänzen Sie die fehlende Aufrufart als Overload, pad(text: string, width: number): string;, oder lassen Sie die Overloads weg, da hier nichts den Rückgabetyp ändert, und behalten Sie eine Signatur mit den Defaults.

Ein einzelner Overload verdeckt die breitere Implementierung

function parse(text: string): number;
function parse(text: string | number): number {
  return Number(text);
}
console.log(parse(42));

Was tsc oder Node.js ausgibt

main.ts(5,19): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

Warum, und die Lösung

Mit einem Overload sehen Aufrufer nur parse(text: string), obwohl die Implementierung auch Zahlen annimmt. Das Handbook sagt, über der Implementierung stets zwei oder mehr Overloads zu schreiben. Hier braucht es gar keinen: Löschen Sie die erste Zeile, dann sehen Aufrufer function parse(text: string | number): number.

Overloads für einen Wert, der beides sein kann

function len(s: string): number;
function len(arr: any[]): number;
function len(x: any) {
  return x.length;
}

console.log(len(Math.random() > 0.5 ? "hello" : [0]));

Was tsc oder Node.js ausgibt

main.ts(7,17): error TS2769: No overload matches this call.

Warum, und die Lösung

Das Argument ist ein String oder ein Array, und TypeScript löst einen Aufruf zu genau einem Overload auf; keiner nimmt beides. Die Zeilen nach der Meldung zeigen, was ein Overload abgelehnt hat. Da beide Overloads eine Zahl zurückgeben, ersetzen Sie sie durch eine Signatur: function len(x: any[] | string) { return x.length; }.

TypeScript im Browser: der Compiler von TypeScript 6.0.3, Apache-2.0, danach die eigene Engine Ihres Browsers. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Overload-Signaturen, dann eine Implementierung

Manche JavaScript-Funktionen lassen sich auf verschiedene Arten aufrufen. makeDate aus dem Handbook nimmt einen Zeitstempel oder Monat, Tag und Jahr. In TypeScript schreiben Sie jede Art als Overload-Signatur auf, einen Funktionskopf ohne Rumpf, der mit ; endet: function makeDate(timestamp: number): Date; und function makeDate(m: number, d: number, y: number): Date;. Danach folgt eine Implementierung mit Rumpf, deren Parameter jeden Overload abdecken: function makeDate(mOrTimestamp: number, d?: number, y?: number): Date { … }. Overloads lassen den Rückgabetyp auch dem Argument folgen. Mit toCents(euros: number): number und toCents(euros: number[]): number[] ist toCents(4.99) eine Zahl. Eine einzige Union-Signatur gäbe number | number[] zurück, und toCents(4.99) + 1 wäre error TS2365.

Aufrufer sehen nur die Overloads

Das Handbook: „The signature of the implementation is not visible from the outside.“ Darum ist makeDate(1, 3) error TS2575: No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments., obwohl d und y in der Implementierung optional sind. Mit nur einem Overload, function fn(x: string): void; function fn() {}, ist der Aufruf fn() error TS2554: Expected 1 arguments, but got 0. Schreiben Sie also zwei oder mehr Overloads. Jeder muss zur Implementierung kompatibel sein, sonst meldet tsc error TS2394: This overload signature is not compatible with its implementation signature. Eine Implementierung mit weniger Parametern gilt trotzdem als kompatibel (B4.1), auch wenn sie ein Argument ignoriert.

Einen Union-Parameter vorziehen

len aus dem Handbook hat zwei Overloads, len(s: string): number und len(arr: any[]): number. len("") und len([0]) sind in Ordnung, aber ein Wert, der beides sein kann, scheitert: len(Math.random() > 0.5 ? "hello" : [0]) ist error TS2769: No overload matches this call. TypeScript löst jeden Aufruf zu genau einem Overload auf, und keiner nimmt beides an. Beide Overloads nehmen ein Argument und geben eine Zahl zurück, also erledigt eine Signatur die Aufgabe besser: function len(x: any[] | string). Aufrufer dürfen beides übergeben. Die Regel des Handbooks: „Always prefer parameters with union types instead of overloads when possible“. Overloads lohnen sich, wenn der Rückgabetyp vom Argument abhängt oder die Argumentzahlen sich unterscheiden, wie bei makeDate.

Quellen

Zuletzt geprüft am 4. Oktober 2026