Published Build3 min read
Your reverse().find() Line Is an Array Copy You No Longer Need
ES2023's findLast() and findLastIndex() walk an array backward in one pass. They have been in Chrome, Firefox, Safari and Node 18 since 2022, so the old workaround has no excuse left.
Written for builders.See today for builders

What happened
- A pattern that appears in almost every codebase is `const lastActive = [...users].reverse().find(u => u.status === 'active')`, which creates a full copy of the array, reverses that copy in place, and then walks it from the start to get one element near the end.
- ES2023 added findLast() to handle finding the last match directly.
- findLast() starts at the last index and works backward in a single pass, does not copy or reverse the original array, and returns the first element for which the predicate returns true, which is the last such element from the array's perspective.
- findLast() takes the same callback as find(): a predicate that receives the current element, its index, and the array.
- Like find(), findLast() returns undefined if no element matches.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
Here is a line that shows up, in some variation, in almost every codebase: `const lastActive = [...users].reverse().find(u => u.status === 'active')` [1]. ES2023 added `findLast()`, which starts at the last index and walks backward in a single pass, so `users.findLast(u => u.status === 'active')` returns the same element without copying or reversing anything [2][3].
The cost of the old idiom is not the search, it is the setup. The spread allocates a full copy of the array, `reverse()` flips that copy in place, and only then does `find()` walk it from the start [1]. That setup work is proportional to the length of the array and happens whether the match is the last element or the first, which is the opposite of what you want when you are looking for something near the end [1]. `findLast()` does none of it and stops at the first element for which the predicate returns true, counting from the back [3].
The API is deliberately unremarkable. `findLast()` takes the same callback shape as `find()`, receiving the element, its index and the array [4], and returns `undefined` when nothing matches [5]. `findLastIndex()` returns the position instead, which is what you want before a `slice` or a `splice`, and returns `-1` on no match, matching `findIndex()` [6][7]. On a four-item transaction list, `findLast(t => t.type === 'credit')` returns the `id: 3` record and `findLastIndex` on the same predicate returns `2` [8][9].
One caveat the grep will surface: `reverse()` operates in place, so any occurrence of `arr.reverse().find(` without a preceding copy is mutating the source array, and swapping in `findLast()` removes a side effect as well as an allocation [2]. That is the sort of thing that reads as a refactor and behaves as a bug fix.
TypeScript has had types for both methods since 4.9, the release that also introduced the `satisfies` operator [10]. The declarations live in `lib.es2023.array.d.ts` and are picked up automatically when your `tsconfig` targets ES2023 or later, or when you add `"ES2023"` to `lib` explicitly [11]. `findLast()` on a `User[]` types as `User | undefined`, `findLastIndex()` as `number` [12].
Runtime support is the least interesting part of this. Both methods are Baseline 2022: Chrome 97 in January 2022, Safari 15.4 in March 2022, Firefox 104 in August 2022, and Node.js since version 18 [13][14]. Cross-engine availability therefore dates from August 2022, when the last of the three shipped [3]. Nothing to install, and no polyfill for any actively maintained runtime [14].
The places this pays off are the ones where "the most recent X matching Y" is the actual requirement: the last error in an audit log, the last undoable entry on a history stack, the last populated row in a dynamic form array before you slice and submit [15].
What to watch: run a search for `reverse().find(` and `reverse().findIndex(` across your repo [16]. Each hit is one of these two methods wrapped in a copy that exists only to flip direction [16]. If your build targets something older than ES2023, check the `lib` setting before the types resolve [11].
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
A pattern that appears in almost every codebase is `const lastActive = [...users].reverse().find(u => u.status === 'active')`, which creates a full copy of the array, reverses that copy in place, and then walks it from the start to get one element near the end.
- [3]
findLast() starts at the last index and works backward in a single pass, does not copy or reverse the original array, and returns the first element for which the predicate returns true, which is the last such element from the array's perspective.
ReportedView cited source - [4]
findLast() takes the same callback as find(): a predicate that receives the current element, its index, and the array.
ReportedView cited source - [6]
findLast() returns the element while findLastIndex() returns its index, which is useful when you need to slice, splice, or reference the position rather than the value.
ReportedView cited source
Sources & coverage · 1 publisher
The reporting this story was synthesized from, earliest first. Every link goes to the original.
- dev.toParsa JiravandAug 14You copy and reverse the array to find the last match. `findLast()` searches from the end directly.
Cited in this coverage: dev.to post by Parsa Jiravand

