/** * Builds an object from the list "elements", where the value of each keyToGroupBy is a subset of values from * "elements" that contains an equal value for the keyToGroupBy "keyToGroupBy" * @template T assignable to a type Record * @template V assignable to string values of T * @param {Array} elements array of record T * @param {keyof T} keyToGroupBy the keyToGroupBy whose string value will be used to group the resulting map * @returns {Record>} */ export const groupBy = , V extends Extract>( elements: Array, keyToGroupBy: keyof T ): Record> => elements.reduce( (groupMap: Record>, element: T) => { const groupByKey: V = element[keyToGroupBy]; // V is constrained to string by Extract in parameter declaration const groupValues: Array = groupMap[groupByKey] || []; return Object.assign({}, groupMap, { [groupByKey]: [...groupValues, element] }); }, {} as Record> );