TypeScript hat dieselben Schleifen wie JavaScript: for, for...of, for...in, while, do...while und die Array-Methode forEach. TypeScript ergänzt die Typen: Die Schleifenvariable von for...of hat den Elementtyp, und ein Schlüssel in for...in ist immer ein string.
Für die meisten Schleifen über Arrays ist for...of die erste Wahl: Es liest sich klar, unterstützt break, continue und await und braucht keine Annotationen.
Die klassische for-Schleife
for (init; condition; update) ist die Schleife zum Zählen, für Schritte größer als eins oder um rückwärts zu laufen. TypeScript leitet den Zähler aus seinem Startwert ab.
Deklariere den Zähler mit let, nicht mit var. Mit let bekommt jeder Durchlauf eine eigene Bindung, sodass ein in der Schleife erzeugter Callback den Wert dieses Durchlaufs sieht.
for...of: Werte von Arrays, Strings und Maps
for...of funktioniert mit allem, was iterierbar ist, und die Schleifenvariable bekommt den passenden Typ. Um auch den Index zu erhalten, durchläufst du array.entries(), das [index, value]-Tupel liefert.
break verlässt die Schleife und continue springt zum nächsten Element, genau wie in einer for-Schleife. Die Details zur Laufzeit (Iterables, Generatoren) stehen auf der JavaScript-Seite zu for...of und for...in.
forEach: kein break, kein await
forEach ruft für jedes Element eine Funktion auf und gibt undefined zurück. Die Parameter des Callbacks werden vom Array her typisiert, Annotationen sind also nicht nötig. Zwei Dinge kann es nicht:
- Früh aufhören.
breakim Callback ist der Compilerfehler TS1107,Jump target cannot cross function boundary.Einreturnbeendet nur den aktuellen Aufruf und wirkt daher wiecontinue. - Auf asynchrone Arbeit warten.
forEachignoriert das Promise, das einasync-Callback zurückgibt.
Die async-Falle übersieht man leicht, weil sie ohne Warnung kompiliert:
Die forEach-Callbacks enden in der Reihenfolge der Timer (10, 20, 30), nachdem die Schleife längst weitergelaufen ist. Die Version mit for...of führt sie nacheinander aus. Für parallele Arbeit, auf die du trotzdem wartest, nimm await Promise.all(items.map(async (item) => { ... })).
for...in: Schlüssel sind Strings
for...in durchläuft die aufzählbaren Eigenschaftsnamen eines Objekts. Der Typ des Schlüssels ist immer string, selbst bei Arrays, wo die Schlüssel die Indizes als Strings sind. Das macht den Indexzugriff auf ein typisiertes Objekt umständlich:
index.ts(5,22): error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ name: string; age: number; }'.
No index signature with a parameter of type 'string' was found on type '{ name: string; age: number; }'.
TypeScript typisiert den Schlüssel absichtlich als string: Zur Laufzeit kann ein Objekt mehr Eigenschaften haben, als sein Typ aufführt (strukturelle Typisierung erlaubt zusätzliche), und for...in durchläuft auch geerbte aufzählbare Eigenschaften. Es kann also nicht versprechen, dass der Schlüssel "name" | "age" ist. Die Lösungen stehen im nächsten Abschnitt. Verwende for...in bei Arrays überhaupt nicht.
Schlüssel und Werte eines Objekts durchlaufen
Object.entries liefert [key, value]-Paare und ist der übliche Weg, über ein Objekt zu iterieren. Object.keys gibt aus demselben Grund wie for...in string[] zurück. Wenn du weißt, dass das Objekt keine zusätzlichen Schlüssel hat, setze eine Assertion auf den Schlüsseltyp.
Für Daten, deren Schlüssel vorher nicht bekannt sind, typisierst du das Objekt als Record<string, number> oder nutzt eine Map; beides wird auf der Seite zum Dictionary behandelt.
while und do...while
while prüft seine Bedingung vor jedem Durchlauf; do...while führt den Rumpf einmal aus, bevor es prüft. Sie passen zu Schleifen, die keine Sammlung durchlaufen, etwa Lesen, bis eine Bedingung erfüllt ist. Narrowing funktioniert darin: Nach einer Prüfung !== undefined in der Bedingung ist die Variable im Rumpf eingeengt.
Labels, break und continue in verschachtelten Schleifen
Ein einfaches break verlässt nur die innerste Schleife. Um eine äußere Schleife zu verlassen, gibst du ihr ein Label und nennst es:
Welche Schleife wofür
| Ziel | Schleife |
|---|---|
| Jedes Element eines Arrays | for (const x of arr) |
| Element und Index | for (const [i, x] of arr.entries()) oder arr.forEach((x, i) => ...) |
| Früh aufhören | for...of mit break oder find, some, every |
| Jeden Schritt abwarten | for...of mit await darin |
| Ein neues Array bauen | map, filter (keine Schleife) |
| Zählen oder in n-Schritten gehen | for (let i = 0; ...; i += n) |
| Schlüssel und Werte eines Objekts | for (const [k, v] of Object.entries(obj)) |
| Einträge einer Map | for (const [k, v] of map) |
| Bis eine Bedingung erfüllt ist | while |
Häufig gestellte Fragen
Wie schreibt man eine for-Schleife in TypeScript?
Genau wie in JavaScript: for (let i = 0; i < 5; i++) { ... }; TypeScript leitet i als number ab. Um die Elemente eines Arrays zu durchlaufen, ist for (const item of items) kürzer, und item bekommt den Elementtyp des Arrays.
Wie breche ich in TypeScript aus forEach aus?
Gar nicht: break im Callback ist der Compilerfehler TS1107 (Jump target cannot cross function boundary), und return beendet nur den aktuellen Callback-Aufruf, wie continue. Nimm for...of mit break oder some/find/every, die von sich aus früh aufhören.
Was ist der Unterschied zwischen for...of und for...in in TypeScript?
for...of durchläuft die Werte eines Iterables (Array-Elemente, Zeichen eines Strings, Map-Einträge) mit ihren echten Typen. for...in durchläuft die aufzählbaren Eigenschaftsschlüssel eines Objekts, immer als string typisiert, Array-Indizes eingeschlossen, ebenfalls als Strings. Nimm for...of für Arrays und Object.entries für Objekte.
Wie durchlaufe ich in TypeScript die Schlüssel und Werte eines Objekts?
Mit for (const [key, value] of Object.entries(obj)). key ist ein string und value die Union der Eigenschaftstypen. Brauchst du key als keyof typeof obj, setze eine Assertion: (Object.keys(obj) as (keyof typeof obj)[]), denn TypeScript typisiert Object.keys absichtlich als string[].
Kann man await in forEach verwenden?
Es kompiliert, aber forEach wartet nicht auf die Promises, die der Callback zurückgibt, also endet die Schleife, bevor die Arbeit erledigt ist. Nimm for...of mit await darin für sequenzielle Arbeit oder await Promise.all(items.map(async (x) => ...)), um sie parallel auszuführen.