From 6e13b8bf54969ad1615d370543f8a0a874afe440 Mon Sep 17 00:00:00 2001 From: gcanti Date: Mon, 19 Feb 2024 13:47:40 +0100 Subject: [PATCH] ReadonlyArray.groupBy: allow for grouping by symbols, closes #2180 --- .changeset/light-mangos-punch.md | 5 +++++ packages/effect/dtslint/ReadonlyArray.ts | 12 ++++++++++-- packages/effect/src/ReadonlyArray.ts | 20 ++++++++++++++------ packages/effect/test/ReadonlyArray.test.ts | 13 +++++++++++++ 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 .changeset/light-mangos-punch.md diff --git a/.changeset/light-mangos-punch.md b/.changeset/light-mangos-punch.md new file mode 100644 index 0000000000..3e730b4dfa --- /dev/null +++ b/.changeset/light-mangos-punch.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +ReadonlyArray.groupBy: allow for grouping by symbols, closes #2180 diff --git a/packages/effect/dtslint/ReadonlyArray.ts b/packages/effect/dtslint/ReadonlyArray.ts index 8d59e4d30e..887d5797ab 100644 --- a/packages/effect/dtslint/ReadonlyArray.ts +++ b/packages/effect/dtslint/ReadonlyArray.ts @@ -19,6 +19,10 @@ declare const pimitiveNumber: number declare const pimitiveNumerOrString: string | number declare const predicateNumbersOrStrings: Predicate.Predicate +const symA = Symbol.for("a") +const symB = Symbol.for("b") +const symC = Symbol.for("c") + // ------------------------------------------------------------------------------------- // isEmptyReadonlyArray // ------------------------------------------------------------------------------------- @@ -99,14 +103,18 @@ pipe(nonEmptyNumbers, ReadonlyArray.map((n) => n + 1)) // groupBy // ------------------------------------------------------------------------------------- -// baseline // $ExpectType Record ReadonlyArray.groupBy([1, 2, 3], String) -// should not return a struct (Record<'positive' | 'negative', ...>) when using string type literals // $ExpectType Record ReadonlyArray.groupBy([1, 2, 3], (n) => n > 0 ? "positive" as const : "negative" as const) +// $ExpectType Record +ReadonlyArray.groupBy(["a", "b"], Symbol.for) + +// $ExpectType Record +ReadonlyArray.groupBy(["a", "b"], (s) => s === "a" ? symA : s === "b" ? symB : symC) + // ------------------------------------------------------------------------------------- // some // ------------------------------------------------------------------------------------- diff --git a/packages/effect/src/ReadonlyArray.ts b/packages/effect/src/ReadonlyArray.ts index cd24312e1a..6b84273369 100644 --- a/packages/effect/src/ReadonlyArray.ts +++ b/packages/effect/src/ReadonlyArray.ts @@ -17,7 +17,7 @@ import * as O from "./Option.js" import * as Order from "./Order.js" import type { Predicate, Refinement } from "./Predicate.js" import { isBoolean } from "./Predicate.js" -import * as RR from "./ReadonlyRecord.js" +import * as ReadonlyRecord from "./ReadonlyRecord.js" import * as Tuple from "./Tuple.js" import type { NoInfer } from "./Types.js" @@ -128,7 +128,7 @@ export const fromIterable = (collection: Iterable): Array => * @category conversions * @since 2.0.0 */ -export const fromRecord: (self: Readonly>) => Array<[K, A]> = RR.toEntries +export const fromRecord: (self: Readonly>) => Array<[K, A]> = ReadonlyRecord.toEntries /** * @category conversions @@ -1334,10 +1334,18 @@ export const group: (self: NonEmptyReadonlyArray) => NonEmptyArray(f: (a: A) => string): (self: Iterable) => Record> - (self: Iterable, f: (a: A) => string): Record> -} = dual(2, (self: Iterable, f: (a: A) => string): Record> => { - const out: Record> = {} + ( + f: (a: A) => K + ): (self: Iterable) => Record, NonEmptyArray> + ( + self: Iterable, + f: (a: A) => K + ): Record, NonEmptyArray> +} = dual(2, ( + self: Iterable, + f: (a: A) => K +): Record, NonEmptyArray> => { + const out: Record> = {} for (const a of self) { const k = f(a) if (Object.prototype.hasOwnProperty.call(out, k)) { diff --git a/packages/effect/test/ReadonlyArray.test.ts b/packages/effect/test/ReadonlyArray.test.ts index d1e063ef6a..379e6baceb 100644 --- a/packages/effect/test/ReadonlyArray.test.ts +++ b/packages/effect/test/ReadonlyArray.test.ts @@ -10,6 +10,10 @@ import * as String from "effect/String" import * as fc from "fast-check" import { assert, describe, expect, it } from "vitest" +const symA = Symbol.for("a") +const symB = Symbol.for("b") +const symC = Symbol.for("c") + describe("ReadonlyArray", () => { it("exports", () => { expect(RA.fromRecord).exist @@ -971,6 +975,15 @@ describe("ReadonlyArray", () => { "6": ["foobar"] } ) + expect(RA.groupBy(["a", "b"], (s) => s === "a" ? symA : s === "b" ? symB : symC)).toStrictEqual({ + [symA]: ["a"], + [symB]: ["b"] + }) + expect(RA.groupBy(["a", "b", "c", "d"], (s) => s === "a" ? symA : s === "b" ? symB : symC)).toStrictEqual({ + [symA]: ["a"], + [symB]: ["b"], + [symC]: ["c", "d"] + }) }) it("match", () => {