Map.groupBy(items, callbackFn) sorts the values of any iterable into groups and returns a Map whose keys are the values your callback computes and whose values are arrays of the items that produced each key. It is a standard ES2024 method (MDN); here you implement it yourself. Its advantage over the plain-object Object.groupBy is that a Map key can be any value — an object, a number, a boolean, even NaN — so keys are never flattened into strings.
function mapGroupBy<T, K>(
items: Iterable<T>,
callbackFn: (item: T, index: number) => K
): Map<K, T[]>;
items is any iterable — an array, a Set, a generator. callbackFn runs once per item with the item and its 0-based index, and whatever it returns becomes that item's group key.
// Group numbers by whether they are even or odd.
mapGroupBy([1, 2, 3, 4, 5], (n) => n % 2);
// → Map(2) { 1 => [1, 3, 5], 0 => [2, 4] }
// Keys can be object references — impossible with a plain-object result.
const eng = { team: 'eng' };
const ops = { team: 'ops' };
mapGroupBy(
[
{ name: 'Ada', dept: eng },
{ name: 'Linus', dept: ops },
{ name: 'Grace', dept: eng },
],
(person) => person.dept
);
// → Map(2) { eng => [Ada, Grace], ops => [Linus] }
new Map() and return it. Do not call the real Map.groupBy.items may be an array, a Set, or a generator. Walk it with for...of, not a numeric index loop, so all of them work.0, 1, 2, … across the iteration, like Array.prototype.map.NaN) share a bucket; different references stay separate. That is the SameValueZero equality a Map uses.