Skip to content

Loops

for user in users { notify(user) }     // for..of semantics — values, not keys
for [k, v] in headers { log(k, v) }
for i in 0..batches { flush(i) }       // → for (let i = 0; i < batches; i++)
for i in 1..=retries { }               // inclusive
while queue.size > 0 { drain() }
while let Some(line) = input.next() { handle(line) }   // refutable head, re-tested each iteration

JS’s key-iterating for..in is removed (use Object.keys), C-style for is replaced by ranges (which exist only in loop heads), and break/continue work as expected. Loops are statements-shaped: they yield no value.

while let binds the let-else refutable pattern set (§6) and re-evaluates the scrutinee each iteration, ending the loop the first time the pattern fails. It is the loop analogue of let-else, with break standing in for the diverging else. Some, constructor, literal, record, array, and as-alias patterns all work, the payload is body-scoped, and there is no else and no value. The pattern must be refutable: an always-matching head (a bare binding, _, or a record/array of only bindings) would spin forever and is refused; write a plain while <condition> instead.

let printLines = async (lines: AsyncIterable<string>) => {
  for await line in lines { console.log(line) }
}
const printLines = async (lines: AsyncIterable<string>) => {
  for await (const line of lines) { console.log(line); }
};

for await iterates asynchronous values inside async arrows or at module top level, with the same patterns and break/continue as for. Ranges are synchronous (HEM3007); inside effect blocks it is refused (HEM4119), so use a Stream, Effect.forEach over an array, or an async helper defined outside the block and lift its Promise with await.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close