Les boucles en TypeScript et les types qu'elles vous donnent
Les boucles en TypeScript
Boucles en TypeScript : for...of, for...in, forEach et types | We.Inc
Découvrez le type que TypeScript donne à la variable de boucle dans for, for...of, for...in et forEach, pourquoi obj[key] échoue dans for...in, et comment parcourir objets et Maps sans risque.
TypeScript a les mêmes boucles que JavaScript : for, for...of, for...in, while, do...while et la méthode de tableau forEach. Ce qu'il ajoute, c'est un type pour chaque variable de boucle. for...of donne le type des éléments, for...in donne toujours des clés string, et forEach donne le type des éléments à son callback, qui ne peut pas s'arrêter en cours de route.
Le type de la variable de boucle
Boucle
Sur
Type de la variable
for (let i = 0; i < a.length; i++)
number[]
i: number
for (const x of a)
number[]
x: number
for (const k in obj)
{ tea: number; cake: number }
k: string
for (const i in a)
number[]
i: string (pas number)
for (const [k, v] of Object.entries(obj))
{ tea: number; cake: number }
k: string, v: number
for (const [k, v] of map)
Map<string, number>
k: string, v: number
a.forEach((x) => ...)
tuple [string, number]
x: string | number
Choisissez un scénario pour voir le code, le type que le compilateur attribue à la variable de boucle, et ce que la boucle affiche à l'exécution. Deux d'entre eux sont volontairement des erreurs de compilation, car ce sont les boucles sur lesquelles on bute le plus souvent en TypeScript.
Choisissez un scénario avec les boutons au-dessus du code.
Lisez la ligne de type pour voir ce que le compilateur pense de la variable de boucle.
Regardez la zone de sortie pour voir ce que la boucle affiche, ou l'erreur exacte de tsc quand elle ne compile pas.
Copiez le code et collez-le dans votre projet ou dans le TypeScript playground.
Préférez for...of pour les tableaux, les chaînes, les Maps et les Sets. La variable reçoit le type des éléments sans cast, et break et continue fonctionnent.
Parcourez un objet avec Object.entries quand vous avez besoin des valeurs. Il vous donne des paires typées et évite l'erreur d'indexation que produit for...in.
Marquez une liste fixe avec as const et la variable de boucle devient une union de ses valeurs littérales, ce qui fonctionne bien dans les instructions switch.
Ne passez pas un callback async à forEach en espérant qu'il attende. Utilisez for...of avec await à l'intérieur, ou Promise.all sur un map.
Questions fréquentes
Pourquoi la clé est-elle une string dans une boucle for...in ?
for...in parcourt les clés string énumérables, y compris celles héritées via la chaîne de prototypes, et TypeScript ne peut pas exclure la présence de clés supplémentaires sur un objet à l'exécution. Typer la clé en keyof T serait une promesse que le langage ne peut pas tenir, donc elle reste string.
Comment corriger "Element implicitly has an 'any' type because expression of type 'string' can't be used to index" ?
Passez à Object.entries(obj) pour obtenir clés et valeurs ensemble, ou castez les clés une seule fois : for (const k of Object.keys(obj) as (keyof typeof obj)[]). Ne castez que si vous savez que l'objet n'a pas de clés supplémentaires.
Peut-on sortir d'un forEach en TypeScript ?
Non. Comme en JavaScript, forEach ne s'arrête que si le callback lève une erreur. Utilisez for...of avec break, ou some() et find(), qui s'arrêtent à la première correspondance.
for...of fonctionne-t-il sur une Map en TypeScript ?
Oui, avec une cible ES2015 ou ultérieure. Chaque tour donne une paire [key, value] typée d'après les génériques de la Map. Pour les cibles plus anciennes, activez downlevelIteration.
Quel type a le compteur d'une boucle for classique ?
let i = 0 infère number, et a[i] donne le type des éléments. Avec noUncheckedIndexedAccess activé, a[i] devient le type des éléments ou undefined, ce qui est plus strict mais plus proche de la réalité.
Les boucles viennent de JavaScript, les types sont la nouveauté
TypeScript n'ajoute aucune syntaxe de boucle. Il compile chaque boucle de cette page vers le même JavaScript, et le guide des boucles JavaScript de ce site explique ce que fait chacune à l'exécution. Ici, l'accent est mis sur le compilateur : quel type reçoit chaque variable de boucle, et les erreurs qui en découlent.
La plupart du temps, l'inférence fait le travail. Vous annotez rarement une variable de boucle, et si vous en ressentez le besoin, c'est généralement que la collection elle-même a besoin d'un meilleur type.
Parcourir des objets sans erreurs
Les objets sont le cas délicat. for...in et Object.keys vous donnent tous deux de simples chaînes, et indexer un objet typé avec une simple chaîne est une erreur en mode strict. Object.entries évite cela en renvoyant des paires [string, value], et son type de valeur vient des valeurs de l'objet.
Si l'objet est une table de correspondance que vous parcourez souvent, envisagez de le typer en Record<string, V> ou de le stocker dans une Map. Les deux rendent évident le type de la variable de boucle et l'erreur disparaît.
Affiner le type dans une boucle
Une boucle sur un tableau d'union, comme (string | number)[], donne une variable de type union. Affinez-la avec typeof dans le corps, et le compilateur suit le type plus étroit pour le reste de cette branche.
L'affinage ne survit pas d'un tour de boucle à l'autre ni dans les callbacks exécutés plus tard, alors vérifiez à nouveau là où la valeur est utilisée.
Boucles et code asynchrone
Attendre une par une avec for...of
Chaque requête attend la précédente. Le tableau de résultats est typé d'après le type de retour de la fonction.
Les lancer ensemble avec Promise.all
map démarre toutes les requêtes à la fois et Promise.all les attend toutes. L'ordre des résultats suit l'ordre des ids.
for...of sur un tableau
s: number
Le type des éléments de number[] passe directement dans la variable de boucle.
for...in sur un objet
k: string
La clé est une simple chaîne, donc l'utiliser pour indexer un objet typé échoue en mode strict.
Object.entries
name: string, price: number
Object.entries renvoie ici [string, number][], donc les deux moitiés de la paire sont typées.
Clés en keyof
k: "tea" | "cake"
Un cast unique indique au compilateur que les clés sont exactement celles déclarées. Sûr seulement si l'objet ne peut pas porter de clés supplémentaires.
for...in sur un tableau
i: string
Les index de tableau arrivent sous forme de chaînes dans for...in, donc en affecter un à une variable number échoue.
for...of sur une Map
item: string, qty: number
Déstructurer l'entrée donne les deux types génériques, dans l'ordre où les entrées ont été ajoutées pour la première fois.
forEach sur un tuple
x: string | number
forEach voit un tuple comme un tableau de l'union de ses types d'éléments, donc affinez avec typeof.
Liste as const
as const conserve les valeurs littérales, donc la variable de boucle est une union que vous pouvez traiter de façon exhaustive dans un switch.