This rule raises an issue when the forEach method is called on arrays, as for…​of loops provide more control flow options.

Why is this an issue?

The usage of forEach limits your control flow options. You cannot use break to exit early or continue to skip iterations, as these statements don’t work inside callback functions. This forces developers to use workarounds like throwing exceptions or complex conditional logic.

Additionally, forEach doesn’t work properly with async/await. The callback function in forEach is called for each element immediately without waiting for any asynchronous operations to complete, which can lead to unexpected behavior when processing arrays that require async operations.

In TypeScript projects, forEach creates a function boundary that breaks type narrowing. Variables that were narrowed to specific types before the loop may lose their narrowed type inside the callback. Additionally, TypeScript’s analysis of variable mutations can be disrupted by the function boundary, potentially missing important usage patterns.

The for…​of loop syntax is also more readable and familiar to developers coming from other programming languages, making the code easier to understand and maintain.

What is the potential impact?

Using forEach instead of for…​of can lead to:

How to fix?

Replace simple forEach calls with for…​of loops.

Non-compliant code example

array.forEach(element => {
    console.log(element);
}); // Noncompliant

array.forEach((element, index) => {
	console.log(element, index);
}); // Noncompliant

// Doesn't work as expected with async operations
urls.forEach(async (url) => {
    const response = await fetch(url); // These requests happen concurrently, not sequentially
    console.log(response.status);
}); // Noncompliant

Compliant code example

for (const element of array) {
    console.log(element);
}

for (const [index, element] of array.entries()) {
	console.log(element, index);
}

// Properly handles async operations sequentially
for (const url of urls) {
    const response = await fetch(url); // These requests happen one after another
    console.log(response.status);
}

Documentation