TypeScript a les mêmes boucles que JavaScript : for, for...of, for...in, while, do...while, et la méthode de tableau forEach. Ce que TypeScript ajoute, ce sont les types : la variable de boucle d'un for...of a le type des éléments, et la clé d'un for...in est toujours un string.
Pour la plupart des boucles sur un tableau, for...of est le bon choix : il se lit clairement, accepte break, continue et await, et ne demande aucune annotation.
La boucle for classique
for (init; condition; update) est la boucle pour compter, avancer par pas de plus de un, ou parcourir à l'envers. TypeScript infère le compteur à partir de sa valeur initiale.
Déclarez le compteur avec let, pas var. Avec let, chaque itération a sa propre liaison, donc un callback créé dans la boucle voit la valeur de cette itération.
for...of : les valeurs des tableaux, chaînes et Maps
for...of fonctionne sur tout ce qui est itérable, et la variable de boucle reçoit le type correspondant. Pour obtenir aussi l'indice, parcourez array.entries(), qui produit des tuples [index, value].
break quitte la boucle et continue passe à l'élément suivant, exactement comme dans une boucle for. Les détails d'exécution (itérables, générateurs) se trouvent sur la page JavaScript for...of et for...in.
forEach : ni break, ni await
forEach appelle une fonction pour chaque élément et renvoie undefined. Les paramètres du callback sont typés à partir du tableau, aucune annotation n'est donc nécessaire. Deux choses lui sont impossibles :
- S'arrêter tôt.
breakdans le callback est l'erreur de compilation TS1107,Jump target cannot cross function boundary.Unreturnne termine que l'appel en cours, il agit donc commecontinue. - Attendre du travail asynchrone.
forEachignore la promesse renvoyée par un callbackasync.
Le piège de l'asynchrone passe facilement inaperçu, car le code compile sans avertissement :
Les callbacks du forEach se terminent dans l'ordre des minuteurs (10, 20, 30), alors que la boucle est déjà passée à la suite. La version for...of les exécute l'un après l'autre. Pour un travail en parallèle que vous attendez quand même, utilisez await Promise.all(items.map(async (item) => { ... })).
for...in : les clés sont des strings
for...in parcourt les noms des propriétés énumérables d'un objet. Le type de la clé est toujours string, même pour les tableaux, dont les clés sont les indices sous forme de chaînes. Cela rend l'indexation d'un objet typé malcommode :
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 type volontairement la clé comme string : à l'exécution, un objet peut avoir plus de propriétés que son type n'en liste (le typage structurel autorise les propriétés en trop), et for...in parcourt aussi les propriétés énumérables héritées. Il ne peut donc pas promettre que la clé vaut "name" | "age". Les solutions sont dans la section suivante. Évitez complètement for...in sur les tableaux.
Parcourir les clés et les valeurs d'un objet
Object.entries donne des paires [key, value] et c'est la façon habituelle de parcourir un objet. Object.keys renvoie string[] pour la même raison que for...in : quand vous savez que l'objet n'a pas de clés en trop, faites une assertion sur le type des clés.
Pour des données dont les clés ne sont pas connues à l'avance, typez l'objet comme un Record<string, number> ou utilisez une Map ; les deux sont couverts sur la page dictionnaire.
while et do...while
while vérifie sa condition avant chaque passage ; do...while exécute le corps une fois avant de vérifier. Elles conviennent aux boucles qui ne parcourent pas une collection, par exemple lire jusqu'à ce qu'une condition soit remplie. Le narrowing fonctionne à l'intérieur : après une vérification !== undefined dans la condition, la variable est affinée dans le corps.
Labels, break et continue dans des boucles imbriquées
Un break simple ne quitte que la boucle la plus interne. Pour quitter une boucle extérieure, donnez-lui un label et nommez ce label :
Quelle boucle utiliser
| Objectif | Boucle |
|---|---|
| Chaque élément d'un tableau | for (const x of arr) |
| Élément et indice | for (const [i, x] of arr.entries()) ou arr.forEach((x, i) => ...) |
| S'arrêter tôt | for...of avec break, ou find, some, every |
| Attendre chaque étape | for...of avec await à l'intérieur |
| Construire un nouveau tableau | map, filter (pas une boucle) |
| Compter ou avancer par pas de n | for (let i = 0; ...; i += n) |
| Clés et valeurs d'un objet | for (const [k, v] of Object.entries(obj)) |
| Entrées d'une Map | for (const [k, v] of map) |
| Jusqu'à une condition | while |
Questions fréquentes
Comment écrire une boucle for en TypeScript ?
Comme en JavaScript : for (let i = 0; i < 5; i++) { ... } ; TypeScript infère i comme number. Pour parcourir les éléments d'un tableau, for (const item of items) est plus court, et item reçoit le type des éléments du tableau.
Comment sortir d'un forEach en TypeScript ?
C'est impossible : break dans le callback est l'erreur de compilation TS1107 (Jump target cannot cross function boundary), et return ne fait que terminer l'appel en cours du callback, comme continue. Utilisez for...of avec break, ou some/find/every, qui s'arrêtent tôt par conception.
Quelle est la différence entre for...of et for...in en TypeScript ?
for...of parcourt les valeurs d'un itérable (éléments d'un tableau, caractères d'une chaîne, entrées d'une Map) avec leurs vrais types. for...in parcourt les clés de propriétés énumérables d'un objet, toujours typées string, y compris les indices d'un tableau sous forme de chaînes. Utilisez for...of pour les tableaux et Object.entries pour les objets.
Comment parcourir les clés et les valeurs d'un objet en TypeScript ?
Utilisez for (const [key, value] of Object.entries(obj)). key est un string et value est l'union des types des propriétés. Si vous avez besoin que key soit typé keyof typeof obj, faites une assertion : (Object.keys(obj) as (keyof typeof obj)[]), car TypeScript type volontairement Object.keys comme string[].
Peut-on utiliser await dans un forEach ?
Ça compile, mais forEach n'attend pas les promesses renvoyées par le callback, donc la boucle se termine avant le travail. Utilisez for...of avec await à l'intérieur pour un traitement séquentiel, ou await Promise.all(items.map(async (x) => ...)) pour l'exécuter en parallèle.