From dc97f6437b6df4d8ea2a1d5e8a7bbbb4411a10da Mon Sep 17 00:00:00 2001 From: Maxim Khramtsov Date: Tue, 1 Oct 2024 16:42:31 +0200 Subject: [PATCH] Add `Tuple.map` (#3658) Co-authored-by: maksim.khramtsov --- .changeset/strong-pans-flash.md | 19 ++++++++++++++++ packages/effect/dtslint/Tuple.ts | 22 +++++++++++++++++++ packages/effect/src/Tuple.ts | 35 ++++++++++++++++++++++++++++++ packages/effect/test/Tuple.test.ts | 4 ++++ 4 files changed, 80 insertions(+) create mode 100644 .changeset/strong-pans-flash.md diff --git a/.changeset/strong-pans-flash.md b/.changeset/strong-pans-flash.md new file mode 100644 index 00000000000..edcf7c9b96a --- /dev/null +++ b/.changeset/strong-pans-flash.md @@ -0,0 +1,19 @@ +--- +"effect": minor +--- + +`Tuple.map` transforms each element of tuple using the given function, treating tuple homomorphically + +```ts +import { pipe, Tuple } from "effect" + +const result = pipe( + // ^? [string, string, string] + ["a", 1, false] as const, + T.map((el) => { + //^? "a" | 1 | false + return el.toString().toUppercase() + }) +) +assert.deepStrictEqual(result, ["A", "1", "FALSE"]) +``` diff --git a/packages/effect/dtslint/Tuple.ts b/packages/effect/dtslint/Tuple.ts index 7ae78c73b20..691898ff82f 100644 --- a/packages/effect/dtslint/Tuple.ts +++ b/packages/effect/dtslint/Tuple.ts @@ -60,3 +60,25 @@ pipe(hole>(), T.at(1)) // $ExpectType number pipe(hole>(), T.at(-1)) + +// ------------------------------------------------------------------------------------- +// map +// ------------------------------------------------------------------------------------- + +// $ExpectType [false, false, false] +pipe( + T.make("a", 1), + T.appendElement(true), + T.map((x) => { + // $ExpectType string | number | boolean + x + return false as const + }) +) + +// $ExpectType [false, false, false] +T.map(["a", 1, false], (x) => { + // $ExpectType string | number | boolean + x + return false as const +}) diff --git a/packages/effect/src/Tuple.ts b/packages/effect/src/Tuple.ts index 82fbe0e1d21..6b3dccc041f 100644 --- a/packages/effect/src/Tuple.ts +++ b/packages/effect/src/Tuple.ts @@ -7,6 +7,7 @@ import * as Equivalence from "./Equivalence.js" import { dual } from "./Function.js" import type { TypeLambda } from "./HKT.js" import * as order from "./Order.js" +import type { TupleOf } from "./Types.js" /** * @category type lambdas @@ -61,6 +62,40 @@ export const getFirst = (self: readonly [L, R]): L => self[0] */ export const getSecond = (self: readonly [L, R]): R => self[1] +/** + * Transforms each element of tuple using the given function, treating tuple homomorphically + * + * @param self - A tuple. + * @param f - The function to transform elements of the tuple. + * + * @example + * import { pipe, Tuple } from "effect" + * + * const result = pipe( + * ["a", 1, false] as const, + * Tuple.map((el) => el.toString().toUpperCase()) + * ) + * assert.deepStrictEqual(result, ['A', '1', 'FALSE']) + * + * @category mapping + * @since 3.9.0 + */ +export const map: { + | [], B>( + fn: (element: T[number]) => B + ): (self: T) => TupleOf + | []>( + self: T, + fn: (element: T[number]) => B + ): TupleOf +} = dual( + 2, + ( + self: TupleOf, + fn: (element: A) => B + ): TupleOf => self.map((element) => fn(element)) as TupleOf +) + /** * Transforms both elements of a tuple using the given functions. * diff --git a/packages/effect/test/Tuple.test.ts b/packages/effect/test/Tuple.test.ts index f52827bfd00..1af9d900800 100644 --- a/packages/effect/test/Tuple.test.ts +++ b/packages/effect/test/Tuple.test.ts @@ -31,6 +31,10 @@ describe("Tuple", () => { })).toEqual(["a!", 2]) }) + it("map", () => { + expect(T.map(["a", 1, false], (x) => x.toString().toUpperCase())).toEqual(["A", "1", "FALSE"]) + }) + it("swap", () => { expect(T.swap(T.make("a", 1))).toEqual([1, "a"]) })