This rule raises an issue when the forEach method is called on arrays, as for…of loops provide better performance and
more control flow options.
The forEach method creates a function call for each array element, which introduces performance overhead compared to native
for…of loops. This overhead becomes more significant with larger arrays.
More importantly, 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.
Using forEach instead of for…of can lead to:
Replace simple forEach calls with for…of loops. This provides better performance and maintains the same
functionality.
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
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);
}