diff --git a/packages/xrpl/src/utils/collections.ts b/packages/xrpl/src/utils/collections.ts index a05d1f4655..31cb9a22e0 100644 --- a/packages/xrpl/src/utils/collections.ts +++ b/packages/xrpl/src/utils/collections.ts @@ -14,20 +14,24 @@ type ValueOf = T[keyof T] */ export function groupBy( array: T[], - iteratee: (value: T, index: number, array: T[]) => string, -): { [p: string]: T[] } { + iteratee: (value: T, index: number, array: T[]) => string | number, +): Record { // eslint-disable-next-line max-params -- need all the params for the fallback - return array.reduce<{ [key: string]: T[] }>(function predicate( - acc, - value, - index, - arrayReference, - ) { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- being safe for js users - ;(acc[iteratee(value, index, arrayReference)] ||= []).push(value) + function predicate( + acc: Record, + value: T, + index: number, + arrayReference: T[], + ): Record { + const key = iteratee(value, index, arrayReference) || 0 + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- Find existing group or create a new one + const group = acc[key] || [] + group.push(value) + acc[key] = group return acc - }, - {}) + } + + return array.reduce(predicate, {}) } /** diff --git a/packages/xrpl/test/utils/collections.test.ts b/packages/xrpl/test/utils/collections.test.ts new file mode 100644 index 0000000000..ba9b93f913 --- /dev/null +++ b/packages/xrpl/test/utils/collections.test.ts @@ -0,0 +1,27 @@ +import { groupBy, omitBy } from '../../src/utils/collections' + +describe('Collection Utils:', () => { + // Inspired from tests at https://github.com/lodash/lodash/blob/main/test/groupBy.spec.js + describe('groupBy', () => { + const array = [6.1, 4.2, 6.3] + + it('should transform keys by `iteratee`', () => { + const actual = groupBy(array, Math.floor) + expect(actual).toEqual({ 4: [4.2], 6: [6.1, 6.3] }) + }) + + it('should transform keys by `iteratee` that returns strings', () => { + const actual = groupBy(array, (item) => Math.floor(item).toString()) + expect(actual).toEqual({ '4': [4.2], '6': [6.1, 6.3] }) + }) + }) + + // Taken from https://github.com/lodash/lodash/blob/main/test/omitBy.spec.js + describe('omitBy', () => { + it('should work with a predicate argument', () => { + const object = { aa: 1, bb: 2, cc: 3, dd: 4 } + const actual = omitBy(object, (num) => num !== 2 && num !== 4) + expect(actual).toEqual({ bb: 2, dd: 4 }) + }) + }) +})