TypeScriptJavaScript

Typescript 5.4 Beta’s New GroupBy Methods

Picture of me, Omari
Omari Thompson-Edwards
Mon Feb 19 2024 4 min

If you're up to date with the latest TypeScript news, you might have read the release notes for TypeScript 5.4 Beta. This has introduced some cool features, one of which is declarations for JavaScript’s new Object.groupBy and Map.groupBy static methods.

What do they do?

Object.groupBy takes an iterable, and a function that decides which "group" each element should be placed in. The function needs to make a "key" for each distinct group, and Object.groupBy uses that key to make an object where every key maps to an array with the original element in it. Map.groupBy is the same thing but it returns a map, which is useful since maps allow you to have anything as a key, among other benefits.

The Old Ways.

My Implementation

JavaScript doesn't necessarily need a groupBy method, we can implement it ourselves. You can find many online, but here's my implementation:

function groupBy<T>(iterable: Iterable<T>, fn: (item: T) => string | number) {
    return [...iterable].reduce<Record<string, T[]>>((groups, curr) => {
        const key = fn(curr);
        const group = groups[key] ?? [];
        group.push(curr);
        return { ...groups, [key]: group };
    }, {});
}

Let's break this down step by step, starting with the outer function:

  • We have a generic function, taking a parameter of whatever type the array stores
  • The parameters for the function are an iterable of type T, and a function that takes a single item in the array and returns a key to group it by
  • I've used the spread operator in order to turn whatever iterable we get into an array.
  • Then we use a reduce to process through our iterable-turned-array

Then inside the reduce:

  • We work out what group the item belongs in using the callback function
  • We get the array, using the null-coalescing operator to give it a default value
    • We add the item to the array for that group
  • Then we return the new set of groups, with our new array added

Here's how to use it:

const people = ['Ava', 'Brie', 'Carl', 'Doomguy', 'Ed', 'Edd', 'Eddy'];

console.log(
    'mine: ',
    groupBy(people, (p) => p.length)
);

Lodash.

Lodash is a library that contains a large selection of utility functions, such as for flattening arrays, sorting arrays, debouncing functions, etc.

To set up Lodash with TypeScript, you’ll need to install it with:

npm i lodash
npm install --save-dev @types/lodash

Then we can use Lodash's built-in method. It works exactly the same, but it also accepts an object property. This means we can make the code a little shorter:

const people = ['Adam', 'Brian', 'Carl', 'Dan', 'Edd'];
console.log(_.groupBy(people, 'length'));

The Proposal.

If you're not familiar with how JavaScript works, I'm going to try and sum it up as quickly as possible.

  • There's a specification called ECMAScript which is the standardized specification for JavaScript
  • This defines the core features of the language that platforms need to implement
  • JavaScript is an implementation of this standard
  • New features have to go through a 4 stage process, from proposal to the 4th final stage

There's a proposal to add Object.groupBy and Map.groupBy which is currently at stage 4. That means the methods are finalized, and ready to be added to ECMAScript, and thus JavaScript. TypeScript 5.4 Beta adds types to these new methods.

What does this mean? In a short while, all the code above will be useless, (which is a good thing). 

Checking support as of the writing of this article, it's widely supported in Chrome, Edge and Firefox, but Safari support at the moment is limited.

Let's compare all 4:

console.log(
    'mine: ',
    groupBy(people, (p) => p.length)
);

console.log(
    'lodash: ',
    _.groupBy(people, (p: string) => p.length)
);

console.log(
    '✨ new ✨',
    Object.groupBy(people, (p) => p.length)
);
console.log(
    '✨ new ✨',
    Map.groupBy(people, (p) => p.length)
);

Code_pR7HcUszLl.png

Pretty similar, the only difference is the map function, since firstly it returns a map (duh), and secondly maps are in insertion order.

So which one should you use? The types for these methods are currently only in TypeScript 5.4, which is in beta, so it might be worth sticking to the Lodash implementation if you're already using Lodash, or implementing them yourself. At the end of the day they're two small, but very convenient utility methods, so whichever implementation you choose won't make or break your app. Either way, thanks for reading!
If you liked this article, why not follow me on Twitter?

read more.

Me
👋 Hey, I'm Omari.

Hey, I'm Omari! I'm a full-stack developer from the UK. I'm currently looking for graduate and freelance software engineering roles, so if you liked this article, feel free to reach out.