I came across a use of .forEach[^mdnForEach] which looked like this: ```ts const areAllItemsValid = (items: MyItem[]): boolean => { let count = 0 items.forEach((item) => { if(!item.isValid()) { return false; } count = count + 1; }) if (count > 3 || count === 0) { // Too many valid things return false; } // Everything must be valid and good return true; } ``` This hides a very tricky to spot scope issue, `items.forEach` is called for every item in the list, regardless of any previous call. At the same time, the result of `forEach` is entirely ignored by the runtime. If this function were to be called with an item that failed the `.isValid()` call, the arrow function _within_ the .forEach would return false. **But that doesn't mean that the invocation of `areAllItemsValid` would return false.** Instead, that false-y return is just ignored by the runtime, never to be seen again. In my experience, almost every call of `.forEach` really meant to be a `.map`[^mdnMap]. The developer was aiming to perform some action on every item in the set and collate the responses into a new set. ```ts let mangledItems = [] items.forEach((item) => { mangledItems.push(mangle(item)) }) // vs const mangledItems = items.map(mangle) ``` The other cases of `.forEach` were often a test to see if "everything" in the set passed some condition or "at least one of" the items in a set passed some condition, or inversely none of them passed. In this case, the functions `Array.prototype.every`[^mdnEvery] and `Array.prototype.some`[^mdnSome] function similar to map but return a single boolean value based on invocation with each item. ```ts // Every item in the items set passed the isEven check const allEven = items.every(isEven) // At least one item in the items set passed the didSucceed check const atLeastOneSuccess = items.some(didSucceed) ``` Getting "comfortable" with `.forEach` also opens up the developer for making a mistake like the following: ```ts const results = await items.forEach(async (item) => { return processData(item) }) ``` > `forEach()` expects a synchronous function — it does not wait for promises The `forEach` function may feel like sexy functional programming, but do not be fooled! Fall back to normal imperative programming and use a `for` loop or a `.map` instead. Yes, yes, I hear you yelling "but for loops have `i` and `i` is a very freshman thing to do!" Most languages have a simplified for/foreach syntax which will do all the heavy lifting for you... ```ts // Yes it's imperative and the nerds may make fun of you // but its clear, and they'll make less fun of you than if // you implemented .forEach wrong! for (const item of items) { await processData(item) } ``` [^mdnForEach]: [MDN Array forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) [^mdnMap]: [MDN Array map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) [^mdnEvery]: [MDN Array every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) [^mdnSome]: [MDN Array some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some)