Loops in TypeScript: for...of, for...in, forEach en types | We.Inc
Zie welk type TypeScript de lusvariabele geeft in for, for...of, for...in en forEach, waarom obj[key] faalt binnen for...in en hoe u veilig objecten en Maps doorloopt.
TypeScript heeft dezelfde loops als JavaScript: for, for...of, for...in, while, do...while en de arraymethode forEach. Wat het toevoegt, is een type voor elke lusvariabele. for...of geeft het elementtype, for...in geeft altijd string-sleutels, en forEach geeft het elementtype aan zijn callback, die niet vroegtijdig kan stoppen.
Het type van de lusvariabele
Loop
Over
Type van de variabele
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 (geen 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) => ...)
[string, number]-tuple
x: string | number
Kies een scenario om de code te zien, het type dat de compiler aan de lusvariabele toekent en wat de loop afdrukt als hij draait. Twee ervan zijn met opzet compileerfouten, omdat dat de loops zijn waar mensen in TypeScript het vaakst op vastlopen.
Kies een scenario met de knoppen boven de code.
Lees de typeregel om te zien wat de compiler denkt dat de lusvariabele is.
Bekijk het uitvoervak voor wat de loop afdrukt, of de exacte tsc-fout als hij niet compileert.
Kopieer de code en plak die in uw project of in de TypeScript-playground.
Gebruik bij voorkeur for...of voor arrays, strings, Maps en Sets. De variabele krijgt het elementtype zonder casten, en break en continue werken.
Loop over een object met Object.entries als u de waarden nodig hebt. U krijgt getypeerde paren en vermijdt de indexeringsfout die for...in oplevert.
Markeer een vaste lijst met as const en de lusvariabele wordt een union van zijn literal-waarden, wat goed werkt in switch-statements.
Geef geen async callback aan forEach in de verwachting dat die wacht. Gebruik for...of met await erin, of Promise.all over een map.
Veelgestelde vragen
Waarom is de sleutel een string in een for...in-loop?
for...in bezoekt opsombare string-sleutels, ook die via de prototypeketen zijn geërfd, en TypeScript kan niet uitsluiten dat een object tijdens runtime extra sleutels heeft. De sleutel typeren als keyof T zou een belofte zijn die de taal niet kan waarmaken, dus blijft het string.
Hoe los ik "Element implicitly has an 'any' type because expression of type 'string' can't be used to index" op?
Stap over op Object.entries(obj) om sleutels en waarden samen te krijgen, of cast de sleutels één keer: for (const k of Object.keys(obj) as (keyof typeof obj)[]). Cast alleen als u weet dat het object geen extra sleutels heeft.
Kan ik in TypeScript uit forEach breken?
Nee. Net als in JavaScript stopt forEach alleen als de callback een fout gooit. Gebruik for...of met break, of some() en find(), die bij de eerste match stoppen.
Werkt for...of op een Map in TypeScript?
Ja, met een target van ES2015 of later. Elke ronde geeft een [key, value]-paar dat is getypeerd vanuit de generics van de Map. Zet voor oudere targets downlevelIteration aan.
Welk type heeft de teller van een klassieke for-loop?
let i = 0 leidt number af, en a[i] geeft het elementtype. Met noUncheckedIndexedAccess aan wordt a[i] het elementtype of undefined, wat strenger is maar dichter bij de waarheid ligt.
De loops zijn JavaScript; de types zijn het nieuwe deel
TypeScript voegt geen loopsyntax toe. Het compileert elke loop op deze pagina naar hetzelfde JavaScript, en de gids over JavaScript-loops op deze site behandelt wat elk ervan tijdens runtime doet. Hier ligt de focus op de compiler: welk type elke lusvariabele krijgt en welke fouten daaruit volgen.
Meestal doet type-inferentie het werk. U annoteert zelden een lusvariabele, en als u daar behoefte aan voelt, betekent het meestal dat de collectie zelf een beter type nodig heeft.
Zonder fouten over objecten loopen
Objecten zijn het lastige geval. for...in en Object.keys geven u allebei gewone strings, en een getypeerd object indexeren met een gewone string is een fout in strict mode. Object.entries vermijdt dat door [string, value]-paren terug te geven, en het waardetype komt uit de waarden van het object.
Als het object een opzoektabel is waar u vaak over loopt, overweeg dan om het te typeren als Record<string, V> of het in een Map op te slaan. Beide maken het type van de lusvariabele duidelijk en de fout verdwijnt.
Vernauwen binnen een loop
Een loop over een union-array, zoals (string | number)[], geeft een union-variabele. Vernauw die met typeof in de body, en de compiler houdt het nauwere type bij voor de rest van die tak.
Vernauwing blijft niet bewaard tussen rondes van de loop of in callbacks die later draaien, dus controleer opnieuw waar de waarde wordt gebruikt.
Loops en async code
Eén voor één awaiten met for...of
Elk verzoek wacht op het vorige. De resultaatarray wordt getypeerd vanuit het returntype van de functie.
Ze samen draaien met Promise.all
map start elk verzoek tegelijk en Promise.all wacht op allemaal. De volgorde van de resultaten volgt de volgorde van de ids.
for...of over array
s: number
Het elementtype van number[] stroomt rechtstreeks in de lusvariabele.
for...in over object
k: string
De sleutel is een gewone string, dus ermee een getypeerd object indexeren faalt in strict mode.
Object.entries
name: string, price: number
Object.entries geeft hier [string, number][] terug, dus beide helften van het paar zijn getypeerd.
Sleutels als keyof
k: "tea" | "cake"
Eén cast vertelt de compiler dat de sleutels precies de gedeclareerde zijn. Alleen veilig als het object geen extra sleutels kan bevatten.
for...in over array
i: string
Array-indexen komen in for...in binnen als strings, dus er één toewijzen aan een number-variabele faalt.
for...of over Map
item: string, qty: number
Het entry destructureren geeft beide generieke types, in de volgorde waarin de entries eerst zijn toegevoegd.
forEach over tuple
x: string | number
forEach ziet een tuple als een array van de union van zijn elementtypes, dus vernauw met typeof.
as const-lijst
as const behoudt de literal-waarden, dus de lusvariabele is een union waarover u volledig kunt switchen.