Fondamentaux des boucles en TypeScript : while, do-while, for, break et continue
Découvrez comment les boucles while, do-while et for de TypeScript évaluent leurs conditions, pourquoi le champ d’application des variables de boucle modifie les résultats, et comment break et continue altèrent le flux.
Sources: Mastering Loops in TypeScript: while, do-while, for, break & continue
Les boucles vous permettent d’exécuter à plusieurs reprises le même bloc de code tant que une condition est remplie, au lieu de copier indéfiniment une instruction. Elles semblent simples, mais la plupart des erreurs liées aux boucles proviennent de trois éléments : le moment où la condition est vérifiée, l’endroit où se trouve la variable de boucle, et l’emplacement des instructions break ou continue à l’intérieur du bloc. Ce guide présente les boucles while, do-while et for de TypeScript à l’aide de petits exemples dont vous pouvez prédire la sortie ligne par ligne, afin que vous puissiez lire et écrire du code d’itération sans surprises.
Pourquoi l’itération est supérieure à la répétition
Imprimer les nombres de 1 à 10 sans boucle nécessite dix appels à console.log. Avec une boucle, vous décrivez l’opération une seule fois et le système d’exécution la répète ; la taille du code reste identique, que vous ayez besoin de dix ou de dix mille répétitions.
La boucle while : vérifier d’abord, puis exécuter
Une boucle while a la forme la plus simple de toutes :
while (condition) {
// statements
}
La condition est évaluée avant chaque itération. Tant qu’elle vaut true, le corps de la boucle s’exécute ; dès qu’elle vaut false, la boucle se termine. Une boucle while fonctionnelle nécessite trois éléments :
- une valeur initiale pour la variable sur laquelle dépend la condition ;
- la condition elle-même ;
- quelque chose dans le corps de la boucle qui fait évoluer cette variable afin que la condition devienne
false.
Si l’on omet le troisième élément, la boucle ne s’arrête jamais, problème abordé ci-dessous.
Décompter de 1 à 10
Ici, les trois éléments sont visibles : i commence à 1, la boucle s’exécute tant que i <= 10, et i++ la fait progresser à chaque itération :
let i: number = 1; // initialization
while (i <= 10) {
console.log(i);
i++;
}
Filtrage des nombres pairs
Pour afficher uniquement les nombres pairs dans cette plage, continuez à parcourir chaque valeur mais ajoutez une vérification à l’intérieur du bloc de code. L’opérateur modulo % renvoie le reste d’une division, donc i % 2 == 0 est vrai exactement lorsque i est pair :
let i: number = 1;
while (i <= 10) {
if (i % 2 == 0) {
console.log(i);
}
i++;
}
Il existe une méthode plus concise pour obtenir un résultat similaire : évitez complètement la vérification et avancez de deux à chaque fois. Notez que cette version commence par 0, ce qui fait qu’elle inclut également 0 dans son résultat :
let i: number = 0;
while (i <= 10) {
console.log(i);
i = i + 2;
}
Résultat : 0, 2, 4, 6, 8, 10
Filtrage des nombres impairs
En inversant la comparaison en != 0, on sélectionne plutôt les valeurs impaires. Commencer par 0 n’a pas d’impact ici, car 0 est pair et est donc filtré :
let i: number = 0;
while (i <= 10) {
if (i % 2 != 0) {
console.log(i);
}
i++;
}
Résultat : 1, 3, 5, 7, 9
Ces exemples utilisent == et != ; les formes strictes === et !== sont généralement préférées car elles ne convertissent jamais les types, bien que le résultat soit identique avec deux nombres.
Décompte à rebours
Pour compter à rebours, commencez par une valeur élevée et diminuez-la tant que la valeur est au moins égale à 1 :
let i: number = 10;
while (i >= 1) {
console.log(i);
i--;
}
Boucles infinies et leurs causes
Une condition while n’est rien d’autre qu’une expression qui évalue à une valeur booléenne, donc while (true) est tout à fait valide. La boucle ci-dessous s’affiche indéfiniment car rien ne la met fin :
let i: number = 1;
while (true) {
console.log(i);
i++;
// no break, no exit condition this runs forever
}
Le plus souvent, les boucles infinies sont accidentelles : la variable de contrôle n’est jamais mise à jour ou se déplace dans le mauvais sens. Une boucle incontrôlable bloque tout le reste sur son thread, ce qui fait apparaître une fenêtre du navigateur ou un processus Node.js comme bloqué. Un while (true) délibéré est acceptable s’il est associé à une sortie explicite, généralement break (expliqué ci-dessous), par exemple dans une logique de « tentative répétée jusqu’à succès ».
La boucle do-while : s’exécute une fois, puis on vérifie
Une boucle do-while place la condition à la fin :
do {
// statements
} while (condition);
Puisque la vérification a lieu après le corps de la boucle, ce dernier s’exécute toujours au moins une fois, quel que soit le résultat de la condition. En revanche, une simple boucle while peut ne pas s’exécuter du tout.
Lorsque la condition est vraie au départ, une boucle do-while se comporte exactement comme une boucle while :
let i: number = 1;
do {
console.log(i);
i++;
} while (i <= 5);
La différence apparaît lorsque la condition est fausse dès le début :
let i: number = 10;
do {
console.log(i);
i++;
} while (i <= 5);
Résultat : 10
Le corps du bloc s’exécute inconditionnellement, affichant 10 et augmentant i à 11. Ce n’est qu’alors que l’expression i <= 5 est évaluée ; elle donne false, ce qui fait que la boucle se termine après une seule itération. Une boucle while (i <= 5) partant de 10 n’affichera rien. Utilisez do-while lorsque l’exécution initiale est obligatoire, par exemple pour afficher une demande au moins une fois.
La boucle for : tout en un seul en-tête
La boucle for est celle que vous utiliserez le plus souvent, surtout lorsque vous savez à l’avance combien de fois répéter ou de combien le compteur doit changer. Elle regroupe l’initialisation, la condition et la mise à jour dans un seul en-tête, ce qui la rend plus compacte que la boucle while équivalente :
for (initialization; condition; increment/decrement) {
// statements
}
L’ordre d’exécution de ces étapes mérite d’être mémorisé :
- L’initialisation s’exécute une seule fois, avant tout le reste (par exemple
let i = 1). - La condition est évaluée. Si elle vaut
true, le corps du boucle s’exécute ; si elle vautfalse, la boucle se termine. - Après le corps du boucle, l’expression de mise à jour s’exécute (par exemple
i++). - Le contrôle revient à l’étape 2, et le cycle se répète jusqu’à ce que la condition devienne
false.
En d’autres termes, l’initialisation a lieu une seule fois, tandis que la condition et la mise à jour ont lieu à chaque cycle.
Décompter de 1 à 10
for (let i = 1; i <= 10; i++) {
console.log(i);
}
Deux façons d’obtenir des nombres pairs
Tout comme avec while, on peut avancer par deux :
for (let i = 2; i <= 10; i += 2) {
console.log(i);
}
ou parcourir chaque valeur et filtrer à l’intérieur du corps du boucle :
for (let i = 2; i <= 10; i++) {
if (i % 2 == 0) {
console.log(i);
}
}
Les deux méthodes affichent la même séquence :
2
4
6
8
10
La méthode de progression effectue moins de travail car elle ne prend en compte que les valeurs paires ; le filtrage est plus flexible lorsque la règle n’est pas une étape fixe, comme « divisible par 3 ou 7 ».
Décompte à rebours
Une mise à jour par décrément exécute la boucle dans le sens inverse :
for (let i = 10; i >= 1; i--) {
console.log(i);
}
Résultat : 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
Pourquoi la variable de boucle vaut-elle 6 après la boucle ?
Le lieu où vous déclarez la variable de boucle influence ce qui reste après la boucle. Dans cet exemple, i est déclaré avant la boucle, et l’en-tête for ne fait que lui attribuer une valeur :
let i: number;
for (i = 1; i <= 5; i++) {
console.log(i);
}
console.log(i);
Résultat : 1, 2, 3, 4, 5, 6
Puisque i se trouve dans le scope externe, l’appel final de console.log(i) parvient encore à l’accéder, conservant la valeur que la boucle a laissée derrière elle. Il s’agit de 6 et non de 5, en raison de l’ordre des opérations décrit précédemment : lors du dernier passage, i vaut 5, le corps de la boucle l’affiche, puis la mise à jour le porte à 6, et ce n’est qu’à ce moment que l’expression 6 <= 5 échoue et met fin à la boucle.
Le style plus courant, for (let i = 1; i <= 5; i++), confère à i un scope de bloc limité à la boucle, de sorte qu’il n’existe plus par la suite. Y faire référence après la boucle provoque une erreur de compilation en TypeScript (“Cannot find name ‘i’”), et en JavaScript pur, cela générerait une erreur ReferenceError au moment de l’exécution. Il est généralement préférable de le déclarer en haut du fichier ; n’utilisez une déclaration externe que lorsque vous avez besoin de sa valeur finale.
Changer le flux avec break et continue
Deux instructions de saut vous permettent de modifier le flux normal d’une boucle depuis l’intérieur de son corps :
breaktermine immédiatement la boucle, quel que soit le nombre d’itérations restantes.continueabandonne uniquement l’itération en cours pour passer à la suivante ; la boucle continue de fonctionner.
Dans une boucle for, continue exécute toujours d’abord l’expression de mise à jour avant de vérifier à nouveau la condition, c’est pourquoi le compteur continue d’avancer.
break : l’emplacement à l’intérieur du corps est important
Ici, la vérification de break a lieu avant l’affichage :
let i: number;
for (i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
console.log(i);
}
Résultat : 1, 2, 3, 4
Lorsque i atteint 5, la boucle s’arrête avant que console.log n’ait eu l’occasion de s’exécuter, donc 5 n’apparaît jamais.
En plaçant l’affichage avant la vérification, le résultat change :
let i: number;
for (i = 1; i <= 10; i++) {
console.log(i);
if (i == 5) {
break;
}
}
Résultat : 1, 2, 3, 4, 5
La condition reste inchangée, pourtant 5 apparaît maintenant car l’affichage a lieu avant la vérification. Avec break et continue, c’est l’ordre des instructions à l’intérieur du corps de la boucle qui détermine le résultat.
continue : sauter une seule valeur
En remplaçant break par continue, on passe de « s’arrêter à 5 » à « sauter 5 » :
let i: number;
for (i = 1; i <= 10; i++) {
if (i == 5) {
continue;
}
console.log(i);
}
Résultat : 1, 2, 3, 4, 6, 7, 8, 9, 10
La boucle continue de fonctionner ; elle se contente de ne pas afficher la valeur pour cette itération.
Sauter tous les nombres impairs
En combinaison avec un filtre, continue envoie chaque valeur impaire directement à l’itération suivante :
let i: number;
for (i = 0; i <= 10; i++) {
if (i % 2 != 0) {
continue;
}
console.log(i);
}
Résultat : 0, 2, 4, 6, 8, 10
Sauter une liste de valeurs spécifiques
La condition peut être aussi complexe que vous le souhaitez. En utilisant l’opérateur logique OU ||, cette boucle saute 3, 5 et 7 :
let i: number;
for (i = 0; i <= 10; i++) {
if (i == 3 || i == 5 || i == 7) {
continue;
}
console.log(i);
}
Résultat : 0, 1, 2, 4, 6, 8, 9, 10
Pour une liste de sauts plus longue, [3, 5, 7].includes(i) ou un Set sont plus appropriés.
Points clés
whilevérifie sa condition avant chaque itération et peut ne pas s’exécuter du tout ;do-whilela vérifie après et s’exécute toujours au moins une fois.- Toute boucle nécessite une mise à jour qui finira par rendre la condition fausse ; sinon, on obtient une boucle infinie qui bloque le thread.
- Dans une boucle
for, l’initialisation s’exécute une seule fois, tandis que la condition et la mise à jour se déroulent à chaque itération, c’est pourquoi un compteur atteint la limite un pas après.
let en tête de boucle le limite au cadre de cette dernière ; le déclarer à l’extérieur permet à sa valeur finale de persister.break termine la boucle tandis que continue saute une itération ; l’endroit où on les place par rapport aux autres instructions influence le résultat.Les conditions déterminent quel code s’exécute ; les boucles déterminent la fréquence d’exécution. Ensemble, elles couvrent la majeure partie des flux de contrôle que vous utiliserez.