From 3d271bacae8479acbba4396304db89b80c9ee813 Mon Sep 17 00:00:00 2001 From: vinassefranche Date: Thu, 22 Aug 2024 10:29:12 +0200 Subject: [PATCH 1/7] Preserve non emptiness for Array.modify and Array.modifyOption --- packages/effect/dtslint/Array.ts | 34 ++++++++++++++++++++++++++++++++ packages/effect/src/Array.ts | 22 +++++++++++++++++---- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/packages/effect/dtslint/Array.ts b/packages/effect/dtslint/Array.ts index 9c6ddb0888..3ff06884a2 100644 --- a/packages/effect/dtslint/Array.ts +++ b/packages/effect/dtslint/Array.ts @@ -1356,3 +1356,37 @@ pipe(new Set([1, 2] as const), Array.replace(0, "a" as const)) // $ExpectType [number | "a", ...(number | "a")[]] pipe(Array.of(1), Array.replace(0, "a" as const)) + +// ------------------------------------------------------------------------------------- +// modify +// ------------------------------------------------------------------------------------- + +// $ExpectType string[] +Array.modify([], 0, () => "a") +// $ExpectType Option +Array.modifyOption([], 0, () => "a") + +// $ExpectType ("a" | 1 | 2)[] +Array.modify(new Set([1, 2] as const), 0, () => "a" as const) +// $ExpectType Option<("a" | 1 | 2)[]> +Array.modifyOption(new Set([1, 2] as const), 0, () => "a" as const) + +// $ExpectType [number | "a", ...(number | "a")[]] +Array.modify(Array.of(1), 0, () => "a" as const) +// $ExpectType Option<[number | "a", ...(number | "a")[]]> +Array.modifyOption(Array.of(1), 0, () => "a" as const) + +// $ExpectType string[] +pipe([], Array.modify(0, () => "a")) +// $ExpectType Option +pipe([], Array.modifyOption(0, () => "a")) + +// $ExpectType ("a" | 1 | 2)[] +pipe(new Set([1, 2] as const), Array.modify(0, () => "a" as const)) +// $ExpectType Option<("a" | 1 | 2)[]> +pipe(new Set([1, 2] as const), Array.modifyOption(0, () => "a" as const)) + +// $ExpectType [number | "a", ...(number | "a")[]] +pipe(Array.of(1), Array.modify(0, () => "a" as const)) +// $ExpectType Option<[number | "a", ...(number | "a")[]]> +pipe(Array.of(1), Array.modifyOption(0, () => "a" as const)) diff --git a/packages/effect/src/Array.ts b/packages/effect/src/Array.ts index 9d6e5f71b4..05bd8e7bb6 100644 --- a/packages/effect/src/Array.ts +++ b/packages/effect/src/Array.ts @@ -1111,8 +1111,15 @@ export const replaceOption: { * @since 2.0.0 */ export const modify: { - (i: number, f: (a: A) => B): (self: Iterable) => Array - (self: Iterable, i: number, f: (a: A) => B): Array + ( + i: number, + f: (a: A) => B + ): = Iterable>(self: S) => ReadonlyArray.With | B> + = Iterable>( + self: S, + i: number, + f: (a: A) => B + ): ReadonlyArray.With | B> } = dual( 3, (self: Iterable, i: number, f: (a: A) => B): Array => @@ -1136,8 +1143,15 @@ export const modify: { * @since 2.0.0 */ export const modifyOption: { - (i: number, f: (a: A) => B): (self: Iterable) => Option> - (self: Iterable, i: number, f: (a: A) => B): Option> + ( + i: number, + f: (a: A) => B + ): = Iterable>(self: S) => Option | B>> + = Iterable>( + self: S, + i: number, + f: (a: A) => B + ): Option | B>> } = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option> => { const out = Array.from(self) if (isOutOfBound(i, out)) { From 2151140e771dbad61bfd59e15830caf55e2d0c14 Mon Sep 17 00:00:00 2001 From: vinassefranche Date: Thu, 22 Aug 2024 10:33:56 +0200 Subject: [PATCH 2/7] Add changeset --- .changeset/curvy-cats-smoke.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/curvy-cats-smoke.md diff --git a/.changeset/curvy-cats-smoke.md b/.changeset/curvy-cats-smoke.md new file mode 100644 index 0000000000..bdd8ad2b3e --- /dev/null +++ b/.changeset/curvy-cats-smoke.md @@ -0,0 +1,5 @@ +--- +"effect": minor +--- + +preserve `Array.modify` `Array.modifyOption` non emptiness From b58cdd4765e6fe4839a8fc3f800fdfbf9fb1236a Mon Sep 17 00:00:00 2001 From: vinassefranche Date: Thu, 22 Aug 2024 11:44:01 +0200 Subject: [PATCH 3/7] Fix bad inference of function parameter --- packages/effect/dtslint/Array.ts | 8 ++++---- packages/effect/src/Array.ts | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/effect/dtslint/Array.ts b/packages/effect/dtslint/Array.ts index 3ff06884a2..7e23f226f4 100644 --- a/packages/effect/dtslint/Array.ts +++ b/packages/effect/dtslint/Array.ts @@ -1371,10 +1371,10 @@ Array.modify(new Set([1, 2] as const), 0, () => "a" as const) // $ExpectType Option<("a" | 1 | 2)[]> Array.modifyOption(new Set([1, 2] as const), 0, () => "a" as const) -// $ExpectType [number | "a", ...(number | "a")[]] -Array.modify(Array.of(1), 0, () => "a" as const) -// $ExpectType Option<[number | "a", ...(number | "a")[]]> -Array.modifyOption(Array.of(1), 0, () => "a" as const) +// $ExpectType [number | string, ...(number | string)[]] +Array.modify(Array.of(1), 0, (n) => n.toString()) +// $ExpectType Option<[number | string, ...(number | string)[]]> +Array.modifyOption(Array.of(1), 0, (n) => n.toString()) // $ExpectType string[] pipe([], Array.modify(0, () => "a")) diff --git a/packages/effect/src/Array.ts b/packages/effect/src/Array.ts index 05bd8e7bb6..a404a054f1 100644 --- a/packages/effect/src/Array.ts +++ b/packages/effect/src/Array.ts @@ -1097,6 +1097,8 @@ export const replaceOption: { (self: Iterable, i: number, b: B): Option> => modifyOption(self, i, () => b) ) +type TypeOfIterable> = T extends Iterable ? A : never + /** * Apply a function to the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. @@ -1118,7 +1120,7 @@ export const modify: { = Iterable>( self: S, i: number, - f: (a: A) => B + f: (a: TypeOfIterable) => B ): ReadonlyArray.With | B> } = dual( 3, @@ -1150,7 +1152,7 @@ export const modifyOption: { = Iterable>( self: S, i: number, - f: (a: A) => B + f: (a: TypeOfIterable) => B ): Option | B>> } = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option> => { const out = Array.from(self) From a47f382a3f9eea0585192f27c80bf8fa2312de2d Mon Sep 17 00:00:00 2001 From: vinassefranche Date: Thu, 22 Aug 2024 12:20:54 +0200 Subject: [PATCH 4/7] Separate modify and modifyOption in dtslint --- packages/effect/dtslint/Array.ts | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/packages/effect/dtslint/Array.ts b/packages/effect/dtslint/Array.ts index 0334562691..402a9fd695 100644 --- a/packages/effect/dtslint/Array.ts +++ b/packages/effect/dtslint/Array.ts @@ -1400,30 +1400,40 @@ pipe(new Set([1, 2] as const), Array.replaceOption(0, "a" as const)) // $ExpectType string[] Array.modify([], 0, () => "a") -// $ExpectType Option -Array.modifyOption([], 0, () => "a") // $ExpectType ("a" | 1 | 2)[] Array.modify(new Set([1, 2] as const), 0, () => "a" as const) -// $ExpectType Option<("a" | 1 | 2)[]> -Array.modifyOption(new Set([1, 2] as const), 0, () => "a" as const) // $ExpectType [number | string, ...(number | string)[]] Array.modify(Array.of(1), 0, (n) => n.toString()) -// $ExpectType Option<[number | string, ...(number | string)[]]> -Array.modifyOption(Array.of(1), 0, (n) => n.toString()) // $ExpectType string[] pipe([], Array.modify(0, () => "a")) -// $ExpectType Option -pipe([], Array.modifyOption(0, () => "a")) // $ExpectType ("a" | 1 | 2)[] pipe(new Set([1, 2] as const), Array.modify(0, () => "a" as const)) -// $ExpectType Option<("a" | 1 | 2)[]> -pipe(new Set([1, 2] as const), Array.modifyOption(0, () => "a" as const)) // $ExpectType [number | "a", ...(number | "a")[]] pipe(Array.of(1), Array.modify(0, () => "a" as const)) + +// ------------------------------------------------------------------------------------- +// modifyOption +// ------------------------------------------------------------------------------------- + +// $ExpectType Option +Array.modifyOption([], 0, () => "a") + +// $ExpectType Option<("a" | 1 | 2)[]> +Array.modifyOption(new Set([1, 2] as const), 0, () => "a" as const) + +// $ExpectType Option<[number | string, ...(number | string)[]]> +Array.modifyOption(Array.of(1), 0, (n) => n.toString()) + +// $ExpectType Option +pipe([], Array.modifyOption(0, () => "a")) + +// $ExpectType Option<("a" | 1 | 2)[]> +pipe(new Set([1, 2] as const), Array.modifyOption(0, () => "a" as const)) + // $ExpectType Option<[number | "a", ...(number | "a")[]]> pipe(Array.of(1), Array.modifyOption(0, () => "a" as const)) From dc32dce4959dbc6abebf919c25d415eeeec9f39c Mon Sep 17 00:00:00 2001 From: vinassefranche Date: Thu, 22 Aug 2024 12:24:32 +0200 Subject: [PATCH 5/7] Use existing type helper --- packages/effect/src/Array.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/effect/src/Array.ts b/packages/effect/src/Array.ts index ac26c33e07..30b8c5c14b 100644 --- a/packages/effect/src/Array.ts +++ b/packages/effect/src/Array.ts @@ -1095,8 +1095,6 @@ export const replaceOption: { (self: Iterable, i: number, b: B): Option> => modifyOption(self, i, () => b) ) -type TypeOfIterable> = T extends Iterable ? A : never - /** * Apply a function to the element at the specified index, creating a new `Array`, * or return a copy of the input if the index is out of bounds. @@ -1118,7 +1116,7 @@ export const modify: { = Iterable>( self: S, i: number, - f: (a: TypeOfIterable) => B + f: (a: ReadonlyArray.Infer) => B ): ReadonlyArray.With | B> } = dual( 3, @@ -1150,7 +1148,7 @@ export const modifyOption: { = Iterable>( self: S, i: number, - f: (a: TypeOfIterable) => B + f: (a: ReadonlyArray.Infer) => B ): Option | B>> } = dual(3, (self: Iterable, i: number, f: (a: A) => B): Option> => { const out = Array.from(self) From ec4acb7e5716f59d2ff803fc16f332d2f0af2300 Mon Sep 17 00:00:00 2001 From: vinassefranche Date: Thu, 22 Aug 2024 12:26:29 +0200 Subject: [PATCH 6/7] Improve dtslint tests --- packages/effect/dtslint/Array.ts | 103 +++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 18 deletions(-) diff --git a/packages/effect/dtslint/Array.ts b/packages/effect/dtslint/Array.ts index 402a9fd695..53ea255d1c 100644 --- a/packages/effect/dtslint/Array.ts +++ b/packages/effect/dtslint/Array.ts @@ -1399,41 +1399,108 @@ pipe(new Set([1, 2] as const), Array.replaceOption(0, "a" as const)) // ------------------------------------------------------------------------------------- // $ExpectType string[] -Array.modify([], 0, () => "a") +Array.modify([], 0, ( + _n // $ExpectType never +) => "a") +// $ExpectType (string | number)[] +Array.modify(numbers, 0, ( + _n // $ExpectType number +) => "a") -// $ExpectType ("a" | 1 | 2)[] -Array.modify(new Set([1, 2] as const), 0, () => "a" as const) +// $ExpectType [number | "a", ...(number | "a")[]] +Array.modify(nonEmptyNumbers, 0, ( + _n // $ExpectType number +) => "a" as const) -// $ExpectType [number | string, ...(number | string)[]] -Array.modify(Array.of(1), 0, (n) => n.toString()) +// $ExpectType ("a" | 1 | 2)[] +Array.modify(new Set([1, 2] as const), 0, ( + _n // $ExpectType 1 | 2 +) => "a" as const) // $ExpectType string[] -pipe([], Array.modify(0, () => "a")) +pipe( + [], + Array.modify(0, ( + _n // $ExpectType never + ) => "a") +) -// $ExpectType ("a" | 1 | 2)[] -pipe(new Set([1, 2] as const), Array.modify(0, () => "a" as const)) +// $ExpectType (string | number)[] +pipe( + numbers, + Array.modify(0, ( + _n // $ExpectType number + ) => "a") +) // $ExpectType [number | "a", ...(number | "a")[]] -pipe(Array.of(1), Array.modify(0, () => "a" as const)) +pipe( + nonEmptyNumbers, + Array.modify(0, ( + _n // $ExpectType number + ) => "a" as const) +) + +// $ExpectType ("a" | 1 | 2)[] +pipe( + new Set([1, 2] as const), + Array.modify(0, ( + _n // $ExpectType 1 | 2 + ) => "a" as const) +) // ------------------------------------------------------------------------------------- // modifyOption // ------------------------------------------------------------------------------------- // $ExpectType Option -Array.modifyOption([], 0, () => "a") +Array.modifyOption([], 0, ( + _n // $ExpectType never +) => "a") -// $ExpectType Option<("a" | 1 | 2)[]> -Array.modifyOption(new Set([1, 2] as const), 0, () => "a" as const) +// $ExpectType Option<(string | number)[]> +Array.modifyOption(numbers, 0, ( + _n // $ExpectType number +) => "a") + +// $ExpectType Option<[number | "a", ...(number | "a")[]]> +Array.modifyOption(nonEmptyNumbers, 0, ( + _n // $ExpectType number +) => "a" as const) -// $ExpectType Option<[number | string, ...(number | string)[]]> -Array.modifyOption(Array.of(1), 0, (n) => n.toString()) +// $ExpectType Option<("a" | 1 | 2)[]> +Array.modifyOption(new Set([1, 2] as const), 0, ( + _n // $ExpectType 1 | 2 +) => "a" as const) // $ExpectType Option -pipe([], Array.modifyOption(0, () => "a")) +pipe( + [], + Array.modifyOption(0, ( + _n // $ExpectType never + ) => "a") +) -// $ExpectType Option<("a" | 1 | 2)[]> -pipe(new Set([1, 2] as const), Array.modifyOption(0, () => "a" as const)) +// $ExpectType Option<(string | number)[]> +pipe( + numbers, + Array.modifyOption(0, ( + _n // $ExpectType number + ) => "a") +) // $ExpectType Option<[number | "a", ...(number | "a")[]]> -pipe(Array.of(1), Array.modifyOption(0, () => "a" as const)) +pipe( + nonEmptyNumbers, + Array.modifyOption(0, ( + _n // $ExpectType number + ) => "a" as const) +) + +// $ExpectType Option<("a" | 1 | 2)[]> +pipe( + new Set([1, 2] as const), + Array.modifyOption(0, ( + _n // $ExpectType 1 | 2 + ) => "a" as const) +) From da5813e69f5c8ea4a31262077db04cc35404b63f Mon Sep 17 00:00:00 2001 From: vinassefranche Date: Thu, 22 Aug 2024 13:54:17 +0200 Subject: [PATCH 7/7] Fix inference of n parameter for data last variant --- packages/effect/src/Array.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/effect/src/Array.ts b/packages/effect/src/Array.ts index 30b8c5c14b..17ce3b9663 100644 --- a/packages/effect/src/Array.ts +++ b/packages/effect/src/Array.ts @@ -1109,10 +1109,10 @@ export const replaceOption: { * @since 2.0.0 */ export const modify: { - ( + = Iterable>( i: number, - f: (a: A) => B - ): = Iterable>(self: S) => ReadonlyArray.With | B> + f: (a: ReadonlyArray.Infer) => B + ): (self: S) => ReadonlyArray.With | B> = Iterable>( self: S, i: number, @@ -1141,10 +1141,10 @@ export const modify: { * @since 2.0.0 */ export const modifyOption: { - ( + = Iterable>( i: number, - f: (a: A) => B - ): = Iterable>(self: S) => Option | B>> + f: (a: ReadonlyArray.Infer) => B + ): (self: S) => Option | B>> = Iterable>( self: S, i: number,