A missing record opens the last item instead. Passing findIndex output directly to Array.at can cause this: findIndex returns -1 for no match, while at(-1) intentionally returns the final element.
Both methods honor their contracts. The composition fails to handle the not-found sentinel. These examples use in-memory data without API requests or record updates.
1. Negative at indices are meaningful
const names = ['Lan', 'Minh', 'Ha'];
console.log(names.at(0)); // Lan
console.log(names.at(-1)); // Ha
console.log(names.at(-2)); // Minh
console.log(names[-1] === undefined); // true
at(-1) counts from the end. Bracket notation reads the property named "-1", absent from this ordinary array. Do not mechanically replace indexing when negative values serve as error markers.
at reads an element without removing it as pop would.
2. A not-found result can select the last record
const users = [
{ id: 'a', name: 'Lan' },
{ id: 'b', name: 'Minh' }
];
const index = users.findIndex(user => user.id === 'missing');
console.log(index); // -1
console.log(users.at(index).name); // Minh
No error is thrown because the last element exists. A populated but incorrect screen can conceal this more easily than an undefined access. Tests using only existing IDs miss it.
The same warning applies to indexOf: handle its -1 sentinel before treating it as a valid relative index.
3. Check the sentinel or use find directly
function findUser(users, id) {
if (!Array.isArray(users) || typeof id !== 'string') {
throw new TypeError('Expected users and a string ID');
}
const index = users.findIndex(user => user.id === id);
return index === -1 ? undefined : users.at(index);
}
const users = [{ id: 'a', name: 'Lan' }, { id: 'b', name: 'Minh' }];
console.log(findUser(users, 'missing') === undefined); // true
console.log(findUser(users, 'a').name); // Lan
console.log(users.find(user => user.id === 'missing') === undefined); // true
This function assumes validated user records. It checks the outer array and ID type rather than providing a full API or sparse-array validator. If only the record is needed, find usually expresses the goal more directly.
Define the caller's missing-record behavior explicitly. Selecting an unrelated first or last record merely to avoid an empty screen can misdirect an operation.
4. Out-of-range reads also return undefined
const values = [undefined, 'B'];
console.log(values.at(0) === undefined); // true
console.log(values.at(99) === undefined); // true
console.log([].at(-1) === undefined); // true
console.log(values.length); // 2
The value alone does not distinguish a present undefined element from an out-of-range access. Check indices and structure when that distinction matters.
at converts its index argument. Validate externally supplied indices explicitly rather than relying on coercion. Intentionally supported negative indices need their own policy.
5. Returned objects remain shared references
Reading an object through at does not copy it. Later property edits can affect other consumers. A non-mutating read does not make subsequent operations independent.
The last item on a paginated page also need not be the newest record globally. That requires an API-defined ordering and scope.
6. Essential cases
- IDs at the beginning, middle and end.
- Missing IDs and empty lists.
- -1 results from findIndex or indexOf.
- Positive and negative out-of-range indices.
- Explicit undefined elements where permitted.
- Shared object references and API ordering.
The snippets ran locally with Node.js, with additional missing-record, type and reference checks. No UI or product API integration was tested. References: Array.prototype.at and Array.prototype.findIndex.
Negative indexing is useful when intentional. Handle failure sentinels before converting them into valid positions.




No comments yet. Be the first to share your thoughts.