diff --git a/benchmarks/performance/flowRight.bench.ts b/benchmarks/performance/flowRight.bench.ts new file mode 100644 index 00000000..ba194fc2 --- /dev/null +++ b/benchmarks/performance/flowRight.bench.ts @@ -0,0 +1,21 @@ +import { bench, describe } from 'vitest'; +import { flowRight as flowRightToolkit } from 'es-toolkit'; +import { flowRight as flowRightLodash } from 'lodash'; + +const flowRight = flowRightToolkit; +const flowRightLo = flowRightLodash; + +describe('flowRight', () => { + const add = (x: number, y: number) => x + y; + const square = (n: number) => n * n; + + bench('es-toolkit/flowRight', () => { + const combined = flowRight(add, square); + combined(1, 2); + }); + + bench('lodash/flowRight', () => { + const combined = flowRightLo(add, square); + combined(1, 2); + }); +}); diff --git a/docs/reference/function/flowRight.md b/docs/reference/function/flowRight.md new file mode 100644 index 00000000..96f3cdd0 --- /dev/null +++ b/docs/reference/function/flowRight.md @@ -0,0 +1,50 @@ +# flowRight + +Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + +This method is like [flow](./flow.md), except that it creates a function that invokes the given functions from right to left. + +## Signature + +```typescript +function flowRight(f: () => R): () => R; +function flowRight(f1: (...args: A) => R): (...args: A) => R; +function flowRight(f2: (a: R1) => R2, f1: (...args: A) => R1): (...args: A) => R2; +function flowRight( + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R3; +function flowRight( + f4: (a: R3) => R4, + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R4; +function flowRight( + f5: (a: R4) => R5, + f4: (a: R3) => R4, + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R5; +function flowRight(...funcs: Array<(...args: any[]) => any>): (...args: any[]) => any; +``` + +### Parameters + +- `funcs` (`Array<(...args: any[]) => any>`): The functions to invoke. + +### Returns + +(`(...args: any[]) => any`): The new composite function. + +## Examples + +```typescript +const add = (x: number, y: number) => x + y; +const square = (n: number) => n * n; + +const combined = flowRight(square, add); +console.log(combined(1, 2)); // => 9 +``` diff --git a/docs/zh_hans/reference/function/flowRight.md b/docs/zh_hans/reference/function/flowRight.md new file mode 100644 index 00000000..2fb62f9f --- /dev/null +++ b/docs/zh_hans/reference/function/flowRight.md @@ -0,0 +1,50 @@ +# flowRight + +创建一个函数,该函数返回调用给定函数的结果,并将创建函数的 `this` 绑定传递给这些函数,每次调用时将上一次调用的返回值作为参数传递给下一次调用。 + +此方法类似于 [flow](./flow.md),但它创建的函数从右到左调用给定的函数。 + +## 签名 + +```typescript +function flowRight(f: () => R): () => R; +function flowRight(f1: (...args: A) => R): (...args: A) => R; +function flowRight(f2: (a: R1) => R2, f1: (...args: A) => R1): (...args: A) => R2; +function flowRight( + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R3; +function flowRight( + f4: (a: R3) => R4, + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R4; +function flowRight( + f5: (a: R4) => R5, + f4: (a: R3) => R4, + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R5; +function flowRight(...funcs: Array<(...args: any[]) => any>): (...args: any[]) => any; +``` + +### 参数 + +- `funcs` (`Array<(...args: any[]) => any>`): 需要调用的函数。 + +### 返回值 + +(`(...args: any[]) => any`): 新的组合函数。 + +## 示例 + +```typescript +const add = (x: number, y: number) => x + y; +const square = (n: number) => n * n; + +const combined = flowRight(square, add); +console.log(combined(1, 2)); // => 9 +``` diff --git a/src/function/flowRight.spec.ts b/src/function/flowRight.spec.ts new file mode 100644 index 00000000..fea95448 --- /dev/null +++ b/src/function/flowRight.spec.ts @@ -0,0 +1,53 @@ +import { describe, it, expect } from 'vitest'; +import { flowRight } from './flowRight'; +import { curry } from '../compat/function/curry'; +import { head } from '../array'; +import { ary } from './ary'; +import { uniq } from '../array'; + +const add = function (x: number, y: number) { + return x + y; +}; + +const square = function (n: number) { + return n * n; +}; + +describe('flowRight', () => { + it(`\`flowRight\` should supply each function with the return value of the previous`, () => { + const fixed = function (n: number) { + return n.toFixed(1); + }; + const combined = flowRight(fixed, square, add); + + expect(combined(1, 2)).toBe('9.0'); + }); + + it(`\`flowRight\` should return a new function`, () => { + const noop = () => {}; + const combined = flowRight(noop); + expect(combined).not.toBe(noop); + }); + + it(`\`flowRight\` should work with a curried function and \`_.head\``, () => { + const curried = curry((i: any) => i); + + const combined = flowRight(curried, head); + + expect(combined([1])).toBe(1); + }); + + it(`\`flowRight\` should work with curried functions with placeholders`, () => { + // TODO change to es-toolkit/compat - map + const map = (array: any[], func: (...args: any[]) => any) => { + return array.map(func); + }; + const curried = curry(ary(map, 2), 2); + const getProp = curried(curried.placeholder, (value: { a: any }) => value.a); + const objects = [{ a: 1 }, { a: 2 }, { a: 1 }]; + + const combined = flowRight(uniq, getProp); + + expect(combined(objects)).toEqual([1, 2]); + }); +}); diff --git a/src/function/flowRight.ts b/src/function/flowRight.ts new file mode 100644 index 00000000..2b4ea05d --- /dev/null +++ b/src/function/flowRight.ts @@ -0,0 +1,163 @@ +import { flow } from './flow.ts'; + +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {() => R} f The function to invoke. + * @returns {() => R} Returns the new composite function. + * + * @example + * function noArgFunc() { + * return 42; + * } + * const combined = flowRight(noArgFunc); + * console.log(combined()); // 42 + */ +export function flowRight(f: () => R): () => R; +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {(...args: A) => R} f1 The function to invoke. + * @returns {(...args: A) => R} Returns the new composite function. + * + * @example + * function oneArgFunc(a: number) { + * return a * 2; + * } + * const combined = flowRight(oneArgFunc); + * console.log(combined(5)); // 10 + */ +export function flowRight(f1: (...args: A) => R): (...args: A) => R; +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {(a: R1) => R2} f2 The function to invoke. + * @param {(...args: A) => R1} f1 The function to invoke. + * @returns {(...args: A) => R2} Returns the new composite function. + * + * @example + * const add = (x: number, y: number) => x + y; + * const square = (n: number) => n * n; + * + * const combined = flowRight(square, add); + * console.log(combined(1, 2)); // 9 + */ +export function flowRight(f2: (a: R1) => R2, f1: (...args: A) => R1): (...args: A) => R2; +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {(a: R2) => R3} f3 The function to invoke. + * @param {(a: R1) => R2} f2 The function to invoke. + * @param {(...args: A) => R1} f1 The function to invoke. + * @returns {(...args: A) => R3} Returns the new composite function. + * + * @example + * const add = (x: number, y: number) => x + y; + * const square = (n: number) => n * n; + * const double = (n: number) => n * 2; + * + * const combined = flowRight(double, square, add); + * console.log(combined(1, 2)); // 18 + */ +export function flowRight( + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R3; +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {(a: R3) => R4} f4 The function to invoke. + * @param {(a: R2) => R3} f3 The function to invoke. + * @param {(a: R1) => R2} f2 The function to invoke. + * @param {(...args: A) => R1} f1 The function to invoke. + * @returns {(...args: A) => R4} Returns the new composite function. + * + * @example + * const add = (x: number, y: number) => x + y; + * const square = (n: number) => n * n; + * const double = (n: number) => n * 2; + * const toStr = (n: number) => n.toString(); + * + * const combined = flowRight(toStr, double, square, add); + * console.log(combined(1, 2)); // '18' + */ +export function flowRight( + f4: (a: R3) => R4, + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R4; +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {(a: R4) => R5} f5 The function to invoke. + * @param {(a: R3) => R4} f4 The function to invoke. + * @param {(a: R2) => R3} f3 The function to invoke. + * @param {(a: R1) => R2} f2 The function to invoke. + * @param {(...args: A) => R1} f1 The function to invoke. + * @returns {(...args: A) => R5} Returns the new composite function. + * + * @example + * const add = (x: number, y: number) => x + y; + * const square = (n: number) => n * n; + * const double = (n: number) => n * 2; + * const toStr = (n: number) => n.toString(); + * const split = (s: string) => s.split(''); + * + * const combined = flowRight(split, toStr, double, square, add); + * console.log(combined(1, 2)); // ['1', '8'] + */ +export function flowRight( + f5: (a: R4) => R5, + f4: (a: R3) => R4, + f3: (a: R2) => R3, + f2: (a: R1) => R2, + f1: (...args: A) => R1 +): (...args: A) => R5; +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {(...args: any[]) => any} funcs The functions to invoke. + * @returns {(...args: any[]) => any} Returns the new composite function. + * + * @example + * const add = (x: number, y: number) => x + y; + * const square = (n: number) => n * n; + * + * const combined = flowRight(square, add); + * console.log(combined(1, 2)); // 9 + */ +export function flowRight(...funcs: Array<(...args: any[]) => any>): (...args: any[]) => any; +/** + * Creates a function that returns the result of invoking the given functions with the `this` binding of the created function, where each successive invocation is supplied the return value of the previous. + * + * This method is like `flow` except that it creates a function that invokes the given functions from right to left. + * + * @param {(...args: any[]) => any} funcs The functions to invoke. + * @returns {(...args: any[]) => any} Returns the new composite function. + * + * @example + * const add = (x: number, y: number) => x + y; + * const square = (n: number) => n * n; + * + * const combined = flowRight(square, add); + * console.log(combined(1, 2)); // 9 + */ +export function flowRight(...funcs: Array<(...args: any[]) => any>): (...args: any[]) => any { + return flow(...funcs.reverse()); +} diff --git a/src/function/index.ts b/src/function/index.ts index 54d4437b..f4c6bd71 100644 --- a/src/function/index.ts +++ b/src/function/index.ts @@ -14,3 +14,4 @@ export { rest } from './rest.ts'; export { curry } from './curry.ts'; export { spread } from './spread.ts'; export { flow } from './flow.ts'; +export { flowRight } from './flowRight.ts';