Typischer setTimeout-Fehler in TypeScript: window vs Node.js

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

„Der falsche setTimeout“: Wie TypeScript Entwickler in den Wahnsinn treibt

\n

Haben Sie jemals einen einfachen Timer in TypeScript geschrieben, und plötzlich begann der Code-Editor alles rot zu unterstreichen? Ein bekanntes Bild: Sie importieren setTimeout, schreiben const timer = setTimeout(...), und TypeScript gibt einen Fehler aus oder schlägt einen unverständlichen Typ vor. Woran liegt das? Es stellt sich heraus, dass es zwei Versionen von setTimeout gibt – eine für den Browser (window), eine für den Server (Node.js). Und TypeScript, der Perfektionist, zwingt uns zur Auswahl.

\n

Dieses Thema ist eines der beliebtesten auf Stack Overflow. Tausende von Entwicklern stolpern über denselben Hürden. Aber wir werden nicht einfach die Antwort kopieren. Wir werden die Ursache des Problems verstehen, nachvollziehen, wie die Typisierung funktioniert, und lernen, Code zu schreiben, der weder im Browser noch in Node.js kaputtgeht.

\n\n

Warum zwei Versionen von setTimeout?

\n

Historisch bedingt lebt JavaScript in zwei Welten: Client-seitig (Browser) und Server-seitig (Node.js). Im Browser ist setTimeout eine Methode des globalen Objekts window. In Node.js ist es eine Funktion aus dem globalen Modul timers. Sie tun dasselbe, aber ihre Typsignaturen unterscheiden sich.

\n

Hier sind die wichtigsten Unterschiede:

\n
    \n
  • Rückgabewert: Im Browser gibt window.setTimeout eine number (Timer-ID) zurück. In Node.js ein Objekt NodeJS.Timeout.
  • \n
  • Kontext: Im Browser ist this innerhalb des Callbacks window (im nicht-strengen Modus). In Node.js das Timer-Objekt.
  • \n
  • Typisierung: TypeScript stellt unterschiedliche Deklarationen für verschiedene Umgebungen bereit. Wenn Sie universellen Code (isomorphe Anwendung) schreiben, entsteht ein Konflikt.
  • \n
\n\n

Wie das Problem im Code aussieht

\n

Stellen Sie sich vor, Sie entwickeln eine Bibliothek, die sowohl auf dem Client als auch auf dem Server funktionieren soll. Sie schreiben diesen Code:

\n
// utils.ts\nexport function delay(ms: number): Promise<void> {\n    return new Promise(resolve => {\n        const timer = setTimeout(resolve, ms);\n        // Welchen Typ hat timer? number oder NodeJS.Timeout?\n    });\n}
\n

TypeScript sieht, dass setTimeout zwei Arten haben kann, und gibt einen Fehler aus: "Type 'Timeout' is not assignable to type 'number'." Oder umgekehrt, abhängig von den Einstellungen in tsconfig.json und den eingebundenen Typen.

\n

Zur Veranschaulichung, so sehen die Typen aus, wenn man sie durch ReturnType betrachtet:

\n
// Im Browser (lib.dom.d.ts)\ntype BrowserTimer = ReturnType<typeof window.setTimeout>; // number\n\n// In Node.js (@types/node)\ntype NodeTimer = ReturnType<typeof setTimeout>; // NodeJS.Timeout
\n\n

Die richtigen Lösungen für verschiedene Szenarien

\n

Betrachten wir vier Ansätze. Wählen Sie den, der zu Ihrem Projekt passt.

\n\n

1. Wenn Sie nur für den Browser schreiben

\n

Der einfachste Fall. Geben Sie einfach den Typ number an und verwenden Sie explizit window.setTimeout:

\n
// browser-timer.ts\nconst timerId: number = window.setTimeout(() => {\n    console.log('Eine Sekunde ist vergangen');\n}, 1000);\n\n// Zum Löschen\nwindow.clearTimeout(timerId);
\n

Warum funktioniert das? In der Browser-Umgebung gibt window.setTimeout immer eine Zahl zurück. TypeScript weiß das, wenn Sie lib: ["dom"] eingebunden haben.

\n\n

2. Wenn Sie nur für Node.js schreiben

\n

Hier ist der Typ NodeJS.Timeout. Verwenden Sie ihn direkt:

\n
// node-timer.ts\nimport { setTimeout } from 'timers'; // expliziter Import zur Klarheit\n\nconst timer: NodeJS.Timeout = setTimeout(() => {\n    console.log('Timer ausgelöst');\n}, 2000);\n\nclearTimeout(timer); // clearTimeout akzeptiert NodeJS.Timeout
\n

Wichtig: In Node.js akzeptiert clearTimeout ebenfalls No

Blogs

Buchempfehlungen