How can use TypeScript groupby on an array of objects by key?

How can use TypeScript groupby on an array of objects by key ? For example, I have an array of car objects:

const cars = [
    { 'make': 'audi', 'model': 'r8', 'year': '2012' },
    { 'make': 'audi', 'model': 'rs5', 'year': '2013' },
    { 'make': 'ford', 'model': 'mustang', 'year': '2012' },
    { 'make': 'ford', 'model': 'fusion', 'year': '2015' },
    { 'make': 'kia', 'model': 'optima', 'year': '2012' },
];

I want to transform this array into a new object where the cars are grouped by their make:

const groupedCars = {
    'audi': [
        { 'model': 'r8', 'year': '2012' },
        { 'model': 'rs5', 'year': '2013' },
    ],
    'ford': [
        { 'model': 'mustang', 'year': '2012' },
        { 'model': 'fusion', 'year': '2015' },
    ],
    'kia': [
        { 'model': 'optima', 'year': '2012' },
    ]
};

How can I achieve this in TypeScript? Is there a way to do this using lodash as well?

You can achieve this using plain TypeScript by iterating through the array and grouping objects manually.

const cars = [
    { 'make': 'audi', 'model': 'r8', 'year': '2012' },
    { 'make': 'audi', 'model': 'rs5', 'year': '2013' },
    { 'make': 'ford', 'model': 'mustang', 'year': '2012' },
    { 'make': 'ford', 'model': 'fusion', 'year': '2015' },
    { 'make': 'kia', 'model': 'optima', 'year': '2012' },
];

type Car = {
    make: string;
    model: string;
    year: string;
};

type GroupedCars = {
    [key: string]: Omit<Car, 'make'>[];
};

const groupedCars: GroupedCars = cars.reduce((acc, car) => {
    if (!acc[car.make]) {
        acc[car.make] = [];
    }
    const { make, ...rest } = car;
    acc[car.make].push(rest);
    return acc;
}, {} as GroupedCars);


console.log(groupedCars);

You can achieve this using plain TypeScript by iterating through the array and grouping objects manually.

Lodash provides a groupBy function which simplifies grouping objects by a key. import _ from ‘lodash’;

const cars = [
    { 'make': 'audi', 'model': 'r8', 'year': '2012' },
    { 'make': 'audi', 'model': 'rs5', 'year': '2013' },
    { 'make': 'ford', 'model': 'mustang', 'year': '2012' },
    { 'make': 'ford', 'model': 'fusion', 'year': '2015' },
    { 'make': 'kia', 'model': 'optima', 'year': '2012' },
];

type Car = {
    make: string;
    model: string;
    year: string;
};

type GroupedCars = {
    [key: string]: Omit<Car, 'make'>[];
};

const groupedCars: GroupedCars = _.groupBy(cars, 'make');

for (const make in groupedCars) {
    groupedCars[make] = groupedCars[make].map(({ make, ...rest }) => rest);
}

console.log(groupedCars);

You can define a custom function to group the array of objects based on the key.

const cars = [
    { 'make': 'audi', 'model': 'r8', 'year': '2012' },
    { 'make': 'audi', 'model': 'rs5', 'year': '2013' },
    { 'make': 'ford', 'model': 'mustang', 'year': '2012' },
    { 'make': 'ford', 'model': 'fusion', 'year': '2015' },
    { 'make': 'kia', 'model': 'optima', 'year': '2012' },
];

type Car = {
    make: string;
    model: string;
    year: string;
};


type GroupedCars = {
    [key: string]: Omit<Car, 'make'>[];
};

function groupByKey<T, K extends keyof T>(array: T[], key: K): { [key: string]: Omit<T, K>[] } {
    return array.reduce((acc, item) => {
        const keyValue = item[key] as unknown as string;
        if (!acc[keyValue]) {
            acc[keyValue] = [];
        }
        const { [key]: removed, ...rest } = item;
        acc[keyValue].push(rest);
        return acc;
    }, {} as { [key: string]: Omit<T, K>[] });
}

const groupedCars: GroupedCars = groupByKey(cars, 'make');

console.log(groupedCars);