mirror of
https://github.com/toss/es-toolkit.git
synced 2024-11-28 03:34:26 +03:00
feat(flow): implement flow (#595)
This commit is contained in:
parent
f70e36bd7b
commit
c051a3165e
21
benchmarks/performance/flow.bench.ts
Normal file
21
benchmarks/performance/flow.bench.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { flow as flowToolkit } from 'es-toolkit';
|
||||
import { flow as flowLodash } from 'lodash';
|
||||
|
||||
const flow = flowToolkit;
|
||||
const flowLo = flowLodash;
|
||||
|
||||
describe('flow', () => {
|
||||
const add = (x: number, y: number) => x + y;
|
||||
const square = (n: number) => n * n;
|
||||
|
||||
bench('es-toolkit/flow', () => {
|
||||
const combined = flow(add, square);
|
||||
combined(1, 2);
|
||||
});
|
||||
|
||||
bench('lodash/flow', () => {
|
||||
const combined = flowLo(add, square);
|
||||
combined(1, 2);
|
||||
});
|
||||
});
|
48
docs/reference/function/flow.md
Normal file
48
docs/reference/function/flow.md
Normal file
@ -0,0 +1,48 @@
|
||||
# flow
|
||||
|
||||
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.
|
||||
|
||||
## Signature
|
||||
|
||||
```typescript
|
||||
function flow<R>(f: () => R): () => R;
|
||||
function flow<A extends any[], R>(f1: (...args: A) => R): (...args: A) => R;
|
||||
function flow<A extends any[], R1, R2>(f1: (...args: A) => R1, f2: (a: R1) => R2): (...args: A) => R2;
|
||||
function flow<A extends any[], R1, R2, R3>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3
|
||||
): (...args: A) => R3;
|
||||
function flow<A extends any[], R1, R2, R3, R4>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3,
|
||||
f4: (a: R3) => R4
|
||||
): (...args: A) => R4;
|
||||
function flow<A extends any[], R1, R2, R3, R4, R5>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3,
|
||||
f4: (a: R3) => R4,
|
||||
f5: (a: R4) => R5
|
||||
): (...args: A) => R5;
|
||||
function flow(...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 = flow(add, square);
|
||||
console.log(combined(1, 2)); // => 9
|
||||
```
|
48
docs/zh_hans/reference/function/flow.md
Normal file
48
docs/zh_hans/reference/function/flow.md
Normal file
@ -0,0 +1,48 @@
|
||||
# flow
|
||||
|
||||
创建一个函数,该函数返回调用给定函数的结果,并将创建函数的 `this` 绑定传递给这些函数,每次调用时将上一次调用的返回值作为参数传递给下一次调用。
|
||||
|
||||
## 签名
|
||||
|
||||
```typescript
|
||||
function flow<R>(f: () => R): () => R;
|
||||
function flow<A extends any[], R>(f1: (...args: A) => R): (...args: A) => R;
|
||||
function flow<A extends any[], R1, R2>(f1: (...args: A) => R1, f2: (a: R1) => R2): (...args: A) => R2;
|
||||
function flow<A extends any[], R1, R2, R3>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3
|
||||
): (...args: A) => R3;
|
||||
function flow<A extends any[], R1, R2, R3, R4>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3,
|
||||
f4: (a: R3) => R4
|
||||
): (...args: A) => R4;
|
||||
function flow<A extends any[], R1, R2, R3, R4, R5>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3,
|
||||
f4: (a: R3) => R4,
|
||||
f5: (a: R4) => R5
|
||||
): (...args: A) => R5;
|
||||
function flow(...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 = flow(add, square);
|
||||
console.log(combined(1, 2)); // => 9
|
||||
```
|
53
src/function/flow.spec.ts
Normal file
53
src/function/flow.spec.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { flow } from './flow';
|
||||
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('flow', () => {
|
||||
it(`\`flow\` should supply each function with the return value of the previous`, () => {
|
||||
const fixed = function (n: number) {
|
||||
return n.toFixed(1);
|
||||
};
|
||||
const combined = flow(add, square, fixed);
|
||||
|
||||
expect(combined(1, 2)).toBe('9.0');
|
||||
});
|
||||
|
||||
it(`\`flow\` should return a new function`, () => {
|
||||
const noop = () => {};
|
||||
const combined = flow(noop);
|
||||
expect(combined).not.toBe(noop);
|
||||
});
|
||||
|
||||
it(`\`flow\` should work with a curried function and \`_.head\``, () => {
|
||||
const curried = curry((i: any) => i);
|
||||
|
||||
const combined = flow(head, curried);
|
||||
|
||||
expect(combined([1])).toBe(1);
|
||||
});
|
||||
|
||||
it(`\`flow\` 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 = flow(getProp, uniq);
|
||||
|
||||
expect(combined(objects)).toEqual([1, 2]);
|
||||
});
|
||||
});
|
155
src/function/flow.ts
Normal file
155
src/function/flow.ts
Normal file
@ -0,0 +1,155 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param {() => R} f The function to invoke.
|
||||
* @returns {() => R} Returns the new composite function.
|
||||
*
|
||||
* @example
|
||||
* function noArgFunc() {
|
||||
* return 42;
|
||||
* }
|
||||
*
|
||||
* const combined = flow(noArgFunc);
|
||||
* console.log(combined()); // 42
|
||||
*/
|
||||
export function flow<R>(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.
|
||||
*
|
||||
* @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 = flow(oneArgFunc);
|
||||
* console.log(combined(5)); // 10
|
||||
*/
|
||||
export function flow<A extends any[], R>(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.
|
||||
*
|
||||
* @param {(...args: A) => R1} f1 The function to invoke.
|
||||
* @param {(a: R1) => R2} f2 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 = flow(add, square);
|
||||
* console.log(combined(1, 2)); // 9
|
||||
*/
|
||||
export function flow<A extends any[], R1, R2>(f1: (...args: A) => R1, f2: (a: R1) => R2): (...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.
|
||||
*
|
||||
* @param {(...args: A) => R1} f1 The function to invoke.
|
||||
* @param {(a: R1) => R2} f2 The function to invoke.
|
||||
* @param {(a: R2) => R3} f3 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 = flow(add, square, double);
|
||||
* console.log(combined(1, 2)); // 18
|
||||
*/
|
||||
export function flow<A extends any[], R1, R2, R3>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3
|
||||
): (...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.
|
||||
*
|
||||
* @param {(...args: A) => R1} f1 The function to invoke.
|
||||
* @param {(a: R1) => R2} f2 The function to invoke.
|
||||
* @param {(a: R2) => R3} f3 The function to invoke.
|
||||
* @param {(a: R3) => R4} f4 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 = flow(add, square, double, toStr);
|
||||
* console.log(combined(1, 2)); // '18'
|
||||
*/
|
||||
export function flow<A extends any[], R1, R2, R3, R4>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3,
|
||||
f4: (a: R3) => R4
|
||||
): (...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.
|
||||
*
|
||||
* @param {(...args: A) => R1} f1 The function to invoke.
|
||||
* @param {(a: R1) => R2} f2 The function to invoke.
|
||||
* @param {(a: R2) => R3} f3 The function to invoke.
|
||||
* @param {(a: R3) => R4} f4 The function to invoke.
|
||||
* @param {(a: R4) => R5} f5 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 = flow(add, square, double, toStr, split);
|
||||
* console.log(combined(1, 2)); // ['1', '8']
|
||||
*/
|
||||
export function flow<A extends any[], R1, R2, R3, R4, R5>(
|
||||
f1: (...args: A) => R1,
|
||||
f2: (a: R1) => R2,
|
||||
f3: (a: R2) => R3,
|
||||
f4: (a: R3) => R4,
|
||||
f5: (a: R4) => R5
|
||||
): (...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.
|
||||
*
|
||||
* @param {Array<(...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 = flow(add, square);
|
||||
* console.log(combined(1, 2)); // 9
|
||||
*/
|
||||
export function flow(...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.
|
||||
*
|
||||
* @param {Array<(...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 = flow(add, square);
|
||||
* console.log(combined(1, 2)); // 9
|
||||
*/
|
||||
export function flow(...funcs: Array<(...args: any[]) => any>): (...args: any[]) => any {
|
||||
return function (this: any, ...args: any[]) {
|
||||
let result = funcs.length ? funcs[0].apply(this, args) : args[0];
|
||||
|
||||
for (let i = 1; i < funcs.length; i++) {
|
||||
result = funcs[i].call(this, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
@ -13,3 +13,4 @@ export { partialRight } from './partialRight.ts';
|
||||
export { rest } from './rest.ts';
|
||||
export { curry } from './curry.ts';
|
||||
export { spread } from './spread.ts';
|
||||
export { flow } from './flow.ts';
|
||||
|
Loading…
Reference in New Issue
Block a user