From 3cc13d239b8436bf49752ce9012a6765c3ed62a2 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Mon, 9 Jan 2023 15:30:17 +0100 Subject: [PATCH 1/6] groupBy return either a Map or an OrderedMap: make the type more precise --- __tests__/groupBy.ts | 69 +++++++++++++++------------- type-definitions/immutable.d.ts | 2 +- type-definitions/ts-tests/groupBy.ts | 12 +++++ 3 files changed, 50 insertions(+), 33 deletions(-) create mode 100644 type-definitions/ts-tests/groupBy.ts diff --git a/__tests__/groupBy.ts b/__tests__/groupBy.ts index 3a2ae09b02..6261cbaa99 100644 --- a/__tests__/groupBy.ts +++ b/__tests__/groupBy.ts @@ -1,4 +1,4 @@ -import { Collection, Map, Seq } from 'immutable'; +import { Collection, Map, Seq, isOrdered, OrderedMap } from 'immutable'; describe('groupBy', () => { it('groups keyed sequence', () => { @@ -14,53 +14,58 @@ describe('groupBy', () => { }); it('groups indexed sequence', () => { - expect( - Seq([1, 2, 3, 4, 5, 6]) - .groupBy(x => x % 2) - .toJS() - ).toEqual({ 1: [1, 3, 5], 0: [2, 4, 6] }); + const group = Seq([1, 2, 3, 4, 5, 6]).groupBy(x => x % 2); + + expect(group).toBeInstanceOf(Map); + expect(group.toJS()).toEqual({ 1: [1, 3, 5], 0: [2, 4, 6] }); }); it('groups to keys', () => { - expect( - Seq([1, 2, 3, 4, 5, 6]) - .groupBy(x => (x % 2 ? 'odd' : 'even')) - .toJS() - ).toEqual({ odd: [1, 3, 5], even: [2, 4, 6] }); + const group = Seq([1, 2, 3, 4, 5, 6]).groupBy(x => + x % 2 ? 'odd' : 'even' + ); + expect(group).toBeInstanceOf(Map); + expect(group.toJS()).toEqual({ odd: [1, 3, 5], even: [2, 4, 6] }); }); it('groups indexed sequences, maintaining indicies when keyed sequences', () => { - expect( - Seq([1, 2, 3, 4, 5, 6]) - .groupBy(x => x % 2) - .toJS() - ).toEqual({ 1: [1, 3, 5], 0: [2, 4, 6] }); - expect( - Seq([1, 2, 3, 4, 5, 6]) - .toKeyedSeq() - .groupBy(x => x % 2) - .toJS() - ).toEqual({ 1: { 0: 1, 2: 3, 4: 5 }, 0: { 1: 2, 3: 4, 5: 6 } }); + const group = Seq([1, 2, 3, 4, 5, 6]).groupBy(x => x % 2); + + expect(group).toBeInstanceOf(Map); + expect(group.toJS()).toEqual({ 1: [1, 3, 5], 0: [2, 4, 6] }); + + const keyedGroup = Seq([1, 2, 3, 4, 5, 6]) + .toKeyedSeq() + .groupBy(x => x % 2); + + expect(keyedGroup).toBeInstanceOf(Map); + expect(keyedGroup.toJS()).toEqual({ + 1: { 0: 1, 2: 3, 4: 5 }, + 0: { 1: 2, 3: 4, 5: 6 }, + }); }); it('has groups that can be mapped', () => { - expect( - Seq([1, 2, 3, 4, 5, 6]) - .groupBy(x => x % 2) - .map(group => group.map(value => value * 10)) - .toJS() - ).toEqual({ 1: [10, 30, 50], 0: [20, 40, 60] }); + const mappedGroup = Seq([1, 2, 3, 4, 5, 6]) + .groupBy(x => x % 2) + .map(group => group.map(value => value * 10)); + + expect(mappedGroup).toBeInstanceOf(Map); + expect(mappedGroup.toJS()).toEqual({ 1: [10, 30, 50], 0: [20, 40, 60] }); }); it('returns an ordered map from an ordered collection', () => { const seq = Seq(['Z', 'Y', 'X', 'Z', 'Y', 'X']); - expect(Collection.isOrdered(seq)).toBe(true); + expect(isOrdered(seq)).toBe(true); const seqGroups = seq.groupBy(x => x); - expect(Collection.isOrdered(seqGroups)).toBe(true); + expect(seqGroups).toBeInstanceOf(OrderedMap); + expect(isOrdered(seqGroups)).toBe(true); const map = Map({ x: 1, y: 2 }); - expect(Collection.isOrdered(map)).toBe(false); + expect(isOrdered(map)).toBe(false); const mapGroups = map.groupBy(x => x); - expect(Collection.isOrdered(mapGroups)).toBe(false); + expect(mapGroups).not.toBeInstanceOf(OrderedMap); + expect(mapGroups).toBeInstanceOf(Map); + expect(isOrdered(mapGroups)).toBe(false); }); }); diff --git a/type-definitions/immutable.d.ts b/type-definitions/immutable.d.ts index bf21c42bf4..0179b75638 100644 --- a/type-definitions/immutable.d.ts +++ b/type-definitions/immutable.d.ts @@ -4600,7 +4600,7 @@ declare namespace Immutable { groupBy( grouper: (value: V, key: K, iter: this) => G, context?: unknown - ): /*Map*/ Seq.Keyed>; + ): Map>; // Side effects diff --git a/type-definitions/ts-tests/groupBy.ts b/type-definitions/ts-tests/groupBy.ts new file mode 100644 index 0000000000..e372841bb0 --- /dev/null +++ b/type-definitions/ts-tests/groupBy.ts @@ -0,0 +1,12 @@ +import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable'; + +{ + // $ExpectType Map> + List(['a', 'b', 'a']).groupBy(v => v); + + // $ExpectType Map> + Set(['a', 'b', 'a']).groupBy(v => v); + + // $ExpectType Map> + Map({a: 'A', b: 'B'}).groupBy(v => v); +} From 8e9f0f8c8025b3194e74fb1af3c747fc82f04444 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Wed, 1 Feb 2023 12:30:55 +0100 Subject: [PATCH 2/6] test all ordered sequences for groupBy --- __tests__/groupBy.ts | 69 ++++++++++++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/__tests__/groupBy.ts b/__tests__/groupBy.ts index 6261cbaa99..230ec1f6b2 100644 --- a/__tests__/groupBy.ts +++ b/__tests__/groupBy.ts @@ -1,6 +1,53 @@ -import { Collection, Map, Seq, isOrdered, OrderedMap } from 'immutable'; +import { + Collection, + Map, + Seq, + isOrdered, + OrderedMap, + List, + OrderedSet, + Set, + Stack, + Record, +} from 'immutable'; describe('groupBy', () => { + it.each` + constructor | constructorIsOrdered | isObject + ${Collection} | ${true} | ${false} + ${List} | ${true} | ${false} + ${Seq} | ${true} | ${false} + ${Set} | ${false} | ${false} + ${Stack} | ${true} | ${false} + ${OrderedSet} | ${true} | ${false} + ${Map} | ${false} | ${true} + ${OrderedMap} | ${true} | ${true} + `( + 'groupBy returns ordered or unordered of the base type is ordered or not: $constructor.name', + ({ constructor, constructorIsOrdered, isObject }) => { + const iterableConstructor = ['a', 'b', 'a', 'c']; + const objectConstructor = { a: 1, b: 2, c: 3, d: 1 }; + + const col = constructor( + isObject ? objectConstructor : iterableConstructor + ); + + const grouped = col.groupBy(v => v); + + // all groupBy should be instance of Map + expect(grouped).toBeInstanceOf(Map); + + // ordered objects should be instance of OrderedMap + expect(isOrdered(col)).toBe(constructorIsOrdered); + expect(isOrdered(grouped)).toBe(constructorIsOrdered); + if (constructorIsOrdered) { + expect(grouped).toBeInstanceOf(OrderedMap); + } else { + expect(grouped).not.toBeInstanceOf(OrderedMap); + } + } + ); + it('groups keyed sequence', () => { const grouped = Seq({ a: 1, b: 2, c: 3, d: 4 }).groupBy(x => x % 2); expect(grouped.toJS()).toEqual({ 1: { a: 1, c: 3 }, 0: { b: 2, d: 4 } }); @@ -16,7 +63,6 @@ describe('groupBy', () => { it('groups indexed sequence', () => { const group = Seq([1, 2, 3, 4, 5, 6]).groupBy(x => x % 2); - expect(group).toBeInstanceOf(Map); expect(group.toJS()).toEqual({ 1: [1, 3, 5], 0: [2, 4, 6] }); }); @@ -24,21 +70,18 @@ describe('groupBy', () => { const group = Seq([1, 2, 3, 4, 5, 6]).groupBy(x => x % 2 ? 'odd' : 'even' ); - expect(group).toBeInstanceOf(Map); expect(group.toJS()).toEqual({ odd: [1, 3, 5], even: [2, 4, 6] }); }); it('groups indexed sequences, maintaining indicies when keyed sequences', () => { const group = Seq([1, 2, 3, 4, 5, 6]).groupBy(x => x % 2); - expect(group).toBeInstanceOf(Map); expect(group.toJS()).toEqual({ 1: [1, 3, 5], 0: [2, 4, 6] }); const keyedGroup = Seq([1, 2, 3, 4, 5, 6]) .toKeyedSeq() .groupBy(x => x % 2); - expect(keyedGroup).toBeInstanceOf(Map); expect(keyedGroup.toJS()).toEqual({ 1: { 0: 1, 2: 3, 4: 5 }, 0: { 1: 2, 3: 4, 5: 6 }, @@ -50,22 +93,6 @@ describe('groupBy', () => { .groupBy(x => x % 2) .map(group => group.map(value => value * 10)); - expect(mappedGroup).toBeInstanceOf(Map); expect(mappedGroup.toJS()).toEqual({ 1: [10, 30, 50], 0: [20, 40, 60] }); }); - - it('returns an ordered map from an ordered collection', () => { - const seq = Seq(['Z', 'Y', 'X', 'Z', 'Y', 'X']); - expect(isOrdered(seq)).toBe(true); - const seqGroups = seq.groupBy(x => x); - expect(seqGroups).toBeInstanceOf(OrderedMap); - expect(isOrdered(seqGroups)).toBe(true); - - const map = Map({ x: 1, y: 2 }); - expect(isOrdered(map)).toBe(false); - const mapGroups = map.groupBy(x => x); - expect(mapGroups).not.toBeInstanceOf(OrderedMap); - expect(mapGroups).toBeInstanceOf(Map); - expect(isOrdered(mapGroups)).toBe(false); - }); }); From 2c735fbb8d3f1b82f57642328e50bf1f4bb99e6b Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Wed, 1 Feb 2023 16:35:39 +0100 Subject: [PATCH 3/6] add type tests for all groupBy --- type-definitions/immutable.d.ts | 235 ++++++++++++++++++++++++++- type-definitions/ts-tests/groupBy.ts | 26 ++- 2 files changed, 258 insertions(+), 3 deletions(-) diff --git a/type-definitions/immutable.d.ts b/type-definitions/immutable.d.ts index 0179b75638..f638a78835 100644 --- a/type-definitions/immutable.d.ts +++ b/type-definitions/immutable.d.ts @@ -709,6 +709,35 @@ declare namespace Immutable { zipper: (...values: Array) => Z, ...collections: Array> ): List; + + /** + * Returns an `OrderedMap` of `List`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { List, Map } = require('immutable') + * const listOfMaps = List([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) + * // OrderedMap { + * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: List [ Map{ "v": 2 } ], + * // } + * ``` + */ + groupBy( + grouper: (value: T, key: number, iter: this) => G, + context?: unknown + ): OrderedMap>; } /** @@ -1470,6 +1499,35 @@ declare namespace Immutable { * @see Collection.Keyed.flip */ flip(): Map; + + /** + * Returns an `Map` of `List`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { Map } = require('immutable') + * const map = Map({ + * a: 1, + * b: 2, + * c: 3, + * d: 1, + * e: 2, + * }) + * const mapOfMaps = map.groupBy(v => `key-${v}`) + * // Map { + * // 'key-1': Map { a: 1, d: 1 }, + * // 'key-2': Map { b: 2, e: 2 }, + * // 'key-3': Map { c: 3 }, + * // } + * ``` + */ + groupBy( + grouper: (value: V, key: K, iter: this) => G, + context?: unknown + ): Map>; } /** @@ -1651,6 +1709,34 @@ declare namespace Immutable { * @see Collection.Keyed.flip */ flip(): OrderedMap; + /** + * Returns an `OrderedMap` of `OrderedMap`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { OrderedMap } = require('immutable') + * const map = OrderedMap({ + * a: 1, + * b: 2, + * c: 3, + * d: 1, + * e: 2, + * }) + * const mapOfMaps = map.groupBy(v => `key-${v}`) + * // OrderedMap { + * // 'key-1': OrderedMap { a: 1, d: 1 }, + * // 'key-2': OrderedMap { b: 2, e: 2 }, + * // 'key-3': OrderedMap { c: 3 }, + * // } + * ``` + */ + groupBy( + grouper: (value: V, key: K, iter: this) => G, + context?: unknown + ): OrderedMap>; } /** @@ -1873,6 +1959,35 @@ declare namespace Immutable { predicate: (this: C, value: T, key: T, iter: this) => unknown, context?: C ): [this, this]; + + /** + * Returns an `Map` of `Set`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { Set, Map } = require('immutable') + * const setOfMaps = Set([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = setOfMaps.groupBy(x => x.get('v')) + * // Map { + * // 0: Set [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: Set [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: Set [ Map{ "v": 2 } ], + * // } + * ``` + */ + groupBy( + grouper: (value: T, key: number, iter: this) => G, + context?: unknown + ): Map>; } /** @@ -2053,6 +2168,35 @@ declare namespace Immutable { zipper: (...values: Array) => Z, ...collections: Array> ): OrderedSet; + + /** + * Returns an `OrderedMap` of `OrderedSet`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { List, Map } = require('immutable') + * const setOfMaps = OrderedSet([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = setOfMaps.groupBy(x => x.get('v')) + * // OrderedMap { + * // 0: OrderedSet [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: OrderedSet [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: OrderedSet [ Map{ "v": 2 } ], + * // } + * ``` + */ + groupBy( + grouper: (value: T, key: number, iter: this) => G, + context?: unknown + ): OrderedMap>; } /** @@ -2301,6 +2445,35 @@ declare namespace Immutable { zipper: (...values: Array) => Z, ...collections: Array> ): Stack; + + /** + * Returns an `OrderedMap` of `Stack`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { Stack, Map } = require('immutable') + * const stackOfMaps = Stack([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = stackOfMaps.groupBy(x => x.get('v')) + * // OrderedMap { + * // 0: Stack [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: Stack [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: Stack [ Map{ "v": 2 } ], + * // } + * ``` + */ + groupBy( + grouper: (value: T, key: number, iter: this) => G, + context?: unknown + ): OrderedMap>; } /** @@ -3415,6 +3588,35 @@ declare namespace Immutable { predicate: (this: C, value: V, key: K, iter: this) => unknown, context?: C ): [this, this]; + + /** + * Returns an `OrderedMap` of `Seq`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { Seq, Map } = require('immutable') + * const seqOfMaps = Seq([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = seqOfMaps.groupBy(x => x.get('v')) + * // OrderedMap { + * // 0: Seq [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: Seq [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: Seq [ Map{ "v": 2 } ], + * // } + * ``` + */ + groupBy( + grouper: (value: V, key: K, iter: this) => G, + context?: unknown + ): OrderedMap>; } /** @@ -3847,6 +4049,35 @@ declare namespace Immutable { ...collections: Array> ): Collection.Indexed; + /** + * Returns an `OrderedMap` of `Collection`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { List, Map } = require('immutable') + * const listOfMaps = Collection([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) + * // OrderedMap { + * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: List [ Map{ "v": 2 } ], + * // } + * ``` + */ + groupBy( + grouper: (value: T, key: number, iter: this) => G, + context?: unknown + ): OrderedMap>; + // Search for value /** @@ -4574,7 +4805,7 @@ declare namespace Immutable { ): this; /** - * Returns a `Collection.Keyed` of `Collection.Keyeds`, grouped by the return + * Returns a `Map` of `Collection`, grouped by the return * value of the `grouper` function. * * Note: This is always an eager operation. @@ -4600,7 +4831,7 @@ declare namespace Immutable { groupBy( grouper: (value: V, key: K, iter: this) => G, context?: unknown - ): Map>; + ): OrderedMap>; // Side effects diff --git a/type-definitions/ts-tests/groupBy.ts b/type-definitions/ts-tests/groupBy.ts index e372841bb0..c8254eab28 100644 --- a/type-definitions/ts-tests/groupBy.ts +++ b/type-definitions/ts-tests/groupBy.ts @@ -1,4 +1,4 @@ -import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable'; +import { List, Map, OrderedMap, Record, Set, Seq, Stack, OrderedSet, DeepCopy, Collection } from 'immutable'; { // $ExpectType Map> @@ -9,4 +9,28 @@ import { List, Map, Record, Set, Seq, DeepCopy, Collection } from 'immutable'; // $ExpectType Map> Map({a: 'A', b: 'B'}).groupBy(v => v); + + // $ExpectType OrderedMap> + Collection(['a', 'b', 'c', 'a']).groupBy(v => v) + + // $ExpectType OrderedMap> + List(['a', 'b', 'c', 'a']).groupBy(v => v) + + // $ExpectType OrderedMap> + Seq(['a', 'b', 'c', 'a']).groupBy(v => v) + + // $ExpectType Map> + Set(['a', 'b', 'c', 'a']).groupBy(v => v) + + // $ExpectType OrderedMap> + Stack(['a', 'b', 'c', 'a']).groupBy(v => v) + + // $ExpectType OrderedMap> + OrderedSet(['a', 'b', 'c', 'a']).groupBy(v => v) + + // $ExpectType Map> + Map({'a': 1, 'b': 2, 'c': 3, 'd' :1}).groupBy(v => $`key-${v}`); + + // $ExpectType OrderedMap> + OrderedMap({'a': 1, 'b': 2, 'c': 3, 'd' :1}).groupBy(v => $`key-${v}`) } From b3fb820cf4e0a2c3d251bf5075d49a68c17da468 Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Wed, 1 Feb 2023 17:49:12 +0100 Subject: [PATCH 4/6] rollback to use Map everywhere (sadly) --- type-definitions/immutable.d.ts | 182 ++++++++++++++++++++++----- type-definitions/ts-tests/groupBy.ts | 37 +++--- 2 files changed, 163 insertions(+), 56 deletions(-) diff --git a/type-definitions/immutable.d.ts b/type-definitions/immutable.d.ts index f638a78835..96d61dedf8 100644 --- a/type-definitions/immutable.d.ts +++ b/type-definitions/immutable.d.ts @@ -734,10 +734,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: T, key: number, iter: this) => G, - context?: unknown - ): OrderedMap>; + // groupBy( + // grouper: (value: T, key: number, iter: this) => G, + // context?: unknown + // ): OrderedMap; } /** @@ -1524,10 +1524,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: V, key: K, iter: this) => G, - context?: unknown - ): Map>; + // groupBy( + // grouper: (value: V, key: K, iter: this) => G, + // context?: unknown + // ): Map>; } /** @@ -1733,10 +1733,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: V, key: K, iter: this) => G, - context?: unknown - ): OrderedMap>; + // groupBy( + // grouper: (value: V, key: K, iter: this) => G, + // context?: unknown + // ): OrderedMap>; } /** @@ -1984,10 +1984,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: T, key: number, iter: this) => G, - context?: unknown - ): Map>; + // groupBy( + // grouper: (value: T, key: number, iter: this) => G, + // context?: unknown + // ): Map>; } /** @@ -2193,10 +2193,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: T, key: number, iter: this) => G, - context?: unknown - ): OrderedMap>; + // groupBy( + // grouper: (value: T, key: number, iter: this) => G, + // context?: unknown + // ): OrderedMap>; } /** @@ -2470,10 +2470,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: T, key: number, iter: this) => G, - context?: unknown - ): OrderedMap>; + // groupBy( + // grouper: (value: T, key: number, iter: this) => G, + // context?: unknown + // ): OrderedMap>; } /** @@ -3142,6 +3142,35 @@ declare namespace Immutable { context?: C ): [this, this]; + /** + * Returns an `OrderedMap` of `Seq.Keyed`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { Seq, Map } = require('immutable') + * const seqOfMaps = Seq([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = seqOfMaps.groupBy(x => x.get('v')) + * // OrderedMap { + * // 0: Seq [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: Seq [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: Seq [ Map{ "v": 2 } ], + * // } + * ``` + */ + // groupBy( + // grouper: (value: V, key: K, iter: this) => G, + // context?: unknown + // ): Map>; + /** * @see Collection.Keyed.flip */ @@ -3322,6 +3351,35 @@ declare namespace Immutable { ...collections: Array> ): Seq.Indexed; + /** + * Returns a `Map` of `Collection.Indexed`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { List, Map } = require('immutable') + * const listOfMaps = List([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) + * // Map { + * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: List [ Map{ "v": 2 } ], + * // } + * ``` + */ + // groupBy( + // grouper: (value: T, key: number, iter: this) => G, + // context?: unknown + // ): Map>; + [Symbol.iterator](): IterableIterator; } @@ -3613,10 +3671,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: V, key: K, iter: this) => G, - context?: unknown - ): OrderedMap>; + // groupBy( + // grouper: (value: V, key: K, iter: this) => G, + // context?: unknown + // ): Map>; } /** @@ -3837,6 +3895,35 @@ declare namespace Immutable { context?: C ): [this, this]; + /** + * Returns an `Map` of `Collection`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { List, Map } = require('immutable') + * const listOfMaps = Collection([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) + * // OrderedMap { + * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: List [ Map{ "v": 2 } ], + * // } + * ``` + */ + // groupBy( + // grouper: (value: V, key: K, iter: this) => G, + // context?: unknown + // ): Map>; + [Symbol.iterator](): IterableIterator<[K, V]>; } @@ -4073,10 +4160,10 @@ declare namespace Immutable { * // } * ``` */ - groupBy( - grouper: (value: T, key: number, iter: this) => G, - context?: unknown - ): OrderedMap>; + // groupBy( + // grouper: (value: T, key: number, iter: this) => G, + // context?: unknown + // ): OrderedMap>; // Search for value @@ -4293,6 +4380,35 @@ declare namespace Immutable { context?: C ): [this, this]; + /** + * Returns a `Map` of `Collection`, grouped by the return + * value of the `grouper` function. + * + * Note: This is always an eager operation. + * + * + * ```js + * const { List, Map } = require('immutable') + * const listOfMaps = List([ + * Map({ v: 0 }), + * Map({ v: 1 }), + * Map({ v: 1 }), + * Map({ v: 0 }), + * Map({ v: 2 }) + * ]) + * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) + * // Map { + * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], + * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], + * // 2: List [ Map{ "v": 2 } ], + * // } + * ``` + */ + // groupBy( + // grouper: (value: T, key: T, iter: this) => G, + // context?: unknown + // ): Map>; + [Symbol.iterator](): IterableIterator; } } @@ -4831,7 +4947,7 @@ declare namespace Immutable { groupBy( grouper: (value: V, key: K, iter: this) => G, context?: unknown - ): OrderedMap>; + ): Map; // Side effects diff --git a/type-definitions/ts-tests/groupBy.ts b/type-definitions/ts-tests/groupBy.ts index c8254eab28..ebd0980abf 100644 --- a/type-definitions/ts-tests/groupBy.ts +++ b/type-definitions/ts-tests/groupBy.ts @@ -1,36 +1,27 @@ import { List, Map, OrderedMap, Record, Set, Seq, Stack, OrderedSet, DeepCopy, Collection } from 'immutable'; { - // $ExpectType Map> - List(['a', 'b', 'a']).groupBy(v => v); + // $ExpectType Map> + Collection(['a', 'b', 'c', 'a']).groupBy(v => v); - // $ExpectType Map> - Set(['a', 'b', 'a']).groupBy(v => v); + // $ExpectType Map> + List(['a', 'b', 'c', 'a']).groupBy(v => v); - // $ExpectType Map> - Map({a: 'A', b: 'B'}).groupBy(v => v); - - // $ExpectType OrderedMap> - Collection(['a', 'b', 'c', 'a']).groupBy(v => v) - - // $ExpectType OrderedMap> - List(['a', 'b', 'c', 'a']).groupBy(v => v) - - // $ExpectType OrderedMap> - Seq(['a', 'b', 'c', 'a']).groupBy(v => v) + // $ExpectType Map> + Seq(['a', 'b', 'c', 'a']).groupBy(v => v); // $ExpectType Map> - Set(['a', 'b', 'c', 'a']).groupBy(v => v) + Set(['a', 'b', 'c', 'a']).groupBy(v => v); - // $ExpectType OrderedMap> - Stack(['a', 'b', 'c', 'a']).groupBy(v => v) + // $ExpectType Map> + Stack(['a', 'b', 'c', 'a']).groupBy(v => v); - // $ExpectType OrderedMap> - OrderedSet(['a', 'b', 'c', 'a']).groupBy(v => v) + // $ExpectType Map> + OrderedSet(['a', 'b', 'c', 'a']).groupBy(v => v); // $ExpectType Map> - Map({'a': 1, 'b': 2, 'c': 3, 'd' :1}).groupBy(v => $`key-${v}`); + Map({ a: 1, b: 2, c: 3, d: 1 }).groupBy(v => `key-${v}`); - // $ExpectType OrderedMap> - OrderedMap({'a': 1, 'b': 2, 'c': 3, 'd' :1}).groupBy(v => $`key-${v}`) + // $ExpectType Map> + OrderedMap({ a: 1, b: 2, c: 3, d: 1 }).groupBy(v => `key-${v}`); } From 122951d2bd5d27a9c575b4fa7720ffa153b7871e Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Wed, 1 Feb 2023 21:12:52 +0100 Subject: [PATCH 5/6] remove comments + add tests for keyed collections --- type-definitions/immutable.d.ts | 347 --------------------------- type-definitions/ts-tests/groupBy.ts | 6 + 2 files changed, 6 insertions(+), 347 deletions(-) diff --git a/type-definitions/immutable.d.ts b/type-definitions/immutable.d.ts index 96d61dedf8..75d9797acb 100644 --- a/type-definitions/immutable.d.ts +++ b/type-definitions/immutable.d.ts @@ -709,35 +709,6 @@ declare namespace Immutable { zipper: (...values: Array) => Z, ...collections: Array> ): List; - - /** - * Returns an `OrderedMap` of `List`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { List, Map } = require('immutable') - * const listOfMaps = List([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) - * // OrderedMap { - * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: List [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: T, key: number, iter: this) => G, - // context?: unknown - // ): OrderedMap; } /** @@ -1499,35 +1470,6 @@ declare namespace Immutable { * @see Collection.Keyed.flip */ flip(): Map; - - /** - * Returns an `Map` of `List`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { Map } = require('immutable') - * const map = Map({ - * a: 1, - * b: 2, - * c: 3, - * d: 1, - * e: 2, - * }) - * const mapOfMaps = map.groupBy(v => `key-${v}`) - * // Map { - * // 'key-1': Map { a: 1, d: 1 }, - * // 'key-2': Map { b: 2, e: 2 }, - * // 'key-3': Map { c: 3 }, - * // } - * ``` - */ - // groupBy( - // grouper: (value: V, key: K, iter: this) => G, - // context?: unknown - // ): Map>; } /** @@ -1709,34 +1651,6 @@ declare namespace Immutable { * @see Collection.Keyed.flip */ flip(): OrderedMap; - /** - * Returns an `OrderedMap` of `OrderedMap`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { OrderedMap } = require('immutable') - * const map = OrderedMap({ - * a: 1, - * b: 2, - * c: 3, - * d: 1, - * e: 2, - * }) - * const mapOfMaps = map.groupBy(v => `key-${v}`) - * // OrderedMap { - * // 'key-1': OrderedMap { a: 1, d: 1 }, - * // 'key-2': OrderedMap { b: 2, e: 2 }, - * // 'key-3': OrderedMap { c: 3 }, - * // } - * ``` - */ - // groupBy( - // grouper: (value: V, key: K, iter: this) => G, - // context?: unknown - // ): OrderedMap>; } /** @@ -1959,35 +1873,6 @@ declare namespace Immutable { predicate: (this: C, value: T, key: T, iter: this) => unknown, context?: C ): [this, this]; - - /** - * Returns an `Map` of `Set`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { Set, Map } = require('immutable') - * const setOfMaps = Set([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = setOfMaps.groupBy(x => x.get('v')) - * // Map { - * // 0: Set [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: Set [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: Set [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: T, key: number, iter: this) => G, - // context?: unknown - // ): Map>; } /** @@ -2168,35 +2053,6 @@ declare namespace Immutable { zipper: (...values: Array) => Z, ...collections: Array> ): OrderedSet; - - /** - * Returns an `OrderedMap` of `OrderedSet`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { List, Map } = require('immutable') - * const setOfMaps = OrderedSet([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = setOfMaps.groupBy(x => x.get('v')) - * // OrderedMap { - * // 0: OrderedSet [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: OrderedSet [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: OrderedSet [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: T, key: number, iter: this) => G, - // context?: unknown - // ): OrderedMap>; } /** @@ -2445,35 +2301,6 @@ declare namespace Immutable { zipper: (...values: Array) => Z, ...collections: Array> ): Stack; - - /** - * Returns an `OrderedMap` of `Stack`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { Stack, Map } = require('immutable') - * const stackOfMaps = Stack([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = stackOfMaps.groupBy(x => x.get('v')) - * // OrderedMap { - * // 0: Stack [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: Stack [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: Stack [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: T, key: number, iter: this) => G, - // context?: unknown - // ): OrderedMap>; } /** @@ -3142,35 +2969,6 @@ declare namespace Immutable { context?: C ): [this, this]; - /** - * Returns an `OrderedMap` of `Seq.Keyed`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { Seq, Map } = require('immutable') - * const seqOfMaps = Seq([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = seqOfMaps.groupBy(x => x.get('v')) - * // OrderedMap { - * // 0: Seq [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: Seq [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: Seq [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: V, key: K, iter: this) => G, - // context?: unknown - // ): Map>; - /** * @see Collection.Keyed.flip */ @@ -3351,35 +3149,6 @@ declare namespace Immutable { ...collections: Array> ): Seq.Indexed; - /** - * Returns a `Map` of `Collection.Indexed`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { List, Map } = require('immutable') - * const listOfMaps = List([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) - * // Map { - * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: List [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: T, key: number, iter: this) => G, - // context?: unknown - // ): Map>; - [Symbol.iterator](): IterableIterator; } @@ -3646,35 +3415,6 @@ declare namespace Immutable { predicate: (this: C, value: V, key: K, iter: this) => unknown, context?: C ): [this, this]; - - /** - * Returns an `OrderedMap` of `Seq`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { Seq, Map } = require('immutable') - * const seqOfMaps = Seq([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = seqOfMaps.groupBy(x => x.get('v')) - * // OrderedMap { - * // 0: Seq [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: Seq [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: Seq [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: V, key: K, iter: this) => G, - // context?: unknown - // ): Map>; } /** @@ -3895,35 +3635,6 @@ declare namespace Immutable { context?: C ): [this, this]; - /** - * Returns an `Map` of `Collection`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { List, Map } = require('immutable') - * const listOfMaps = Collection([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) - * // OrderedMap { - * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: List [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: V, key: K, iter: this) => G, - // context?: unknown - // ): Map>; - [Symbol.iterator](): IterableIterator<[K, V]>; } @@ -4136,35 +3847,6 @@ declare namespace Immutable { ...collections: Array> ): Collection.Indexed; - /** - * Returns an `OrderedMap` of `Collection`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { List, Map } = require('immutable') - * const listOfMaps = Collection([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) - * // OrderedMap { - * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: List [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: T, key: number, iter: this) => G, - // context?: unknown - // ): OrderedMap>; - // Search for value /** @@ -4380,35 +4062,6 @@ declare namespace Immutable { context?: C ): [this, this]; - /** - * Returns a `Map` of `Collection`, grouped by the return - * value of the `grouper` function. - * - * Note: This is always an eager operation. - * - * - * ```js - * const { List, Map } = require('immutable') - * const listOfMaps = List([ - * Map({ v: 0 }), - * Map({ v: 1 }), - * Map({ v: 1 }), - * Map({ v: 0 }), - * Map({ v: 2 }) - * ]) - * const groupsOfMaps = listOfMaps.groupBy(x => x.get('v')) - * // Map { - * // 0: List [ Map{ "v": 0 }, Map { "v": 0 } ], - * // 1: List [ Map{ "v": 1 }, Map { "v": 1 } ], - * // 2: List [ Map{ "v": 2 } ], - * // } - * ``` - */ - // groupBy( - // grouper: (value: T, key: T, iter: this) => G, - // context?: unknown - // ): Map>; - [Symbol.iterator](): IterableIterator; } } diff --git a/type-definitions/ts-tests/groupBy.ts b/type-definitions/ts-tests/groupBy.ts index ebd0980abf..dc9bfc81c0 100644 --- a/type-definitions/ts-tests/groupBy.ts +++ b/type-definitions/ts-tests/groupBy.ts @@ -4,12 +4,18 @@ import { List, Map, OrderedMap, Record, Set, Seq, Stack, OrderedSet, DeepCopy, C // $ExpectType Map> Collection(['a', 'b', 'c', 'a']).groupBy(v => v); + // $ExpectType Map> + Collection({ a: 1, b: 2, c: 3, d: 1 }).groupBy(v => `key-${v}`); + // $ExpectType Map> List(['a', 'b', 'c', 'a']).groupBy(v => v); // $ExpectType Map> Seq(['a', 'b', 'c', 'a']).groupBy(v => v); + // $ExpectType Map> + Seq({ a: 1, b: 2, c: 3, d: 1 }).groupBy(v => `key-${v}`); + // $ExpectType Map> Set(['a', 'b', 'c', 'a']).groupBy(v => v); From b6ac8b9f7bbc0c0ae910628184ef37587067b6ee Mon Sep 17 00:00:00 2001 From: Julien Deniau Date: Wed, 1 Feb 2023 21:15:39 +0100 Subject: [PATCH 6/6] update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 194929f739..b531903e67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Dates are formatted as YYYY-MM-DD. +## Unreleased + +- TypeScript: `groupBy` return either a `Map` or an `OrderedMap`: make the type more precise than base `Collection` [#1924](https://github.com/immutable-js/immutable-js/pull/1924) + ## [4.2.2] - 2023-01-02 - [Flow] Add type for `partition` method [#1920](https://github.com/immutable-js/immutable-js/pull/1920) by [Dagur](https://github.com/Dagur)