From 12f859ffe88afceedcf260004608868555a44380 Mon Sep 17 00:00:00 2001 From: seungro Date: Sat, 21 Sep 2024 02:40:19 +0900 Subject: [PATCH 01/30] feat. initialize script for fp --- .../_internal/getter/functionDeclaration.ts | 42 +++++++ .scripts/fp/_internal/getter/typedParam.ts | 8 ++ .scripts/fp/_internal/types.ts | 6 + .../validator/functionDeclaration.ts | 15 +++ .scripts/fp/_internal/validator/params.ts | 13 ++ .scripts/fp/create-fp-version.sh | 6 + .scripts/fp/toPipable.ts | 113 ++++++++++++++++++ package.json | 4 +- src/fp/object/mapKeys.ts | 46 +++++++ src/fp/object/omit.ts | 33 +++++ src/fp/object/omitBy.ts | 47 ++++++++ yarn.lock | 3 +- 12 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 .scripts/fp/_internal/getter/functionDeclaration.ts create mode 100644 .scripts/fp/_internal/getter/typedParam.ts create mode 100644 .scripts/fp/_internal/types.ts create mode 100644 .scripts/fp/_internal/validator/functionDeclaration.ts create mode 100644 .scripts/fp/_internal/validator/params.ts create mode 100644 .scripts/fp/create-fp-version.sh create mode 100644 .scripts/fp/toPipable.ts create mode 100644 src/fp/object/mapKeys.ts create mode 100644 src/fp/object/omit.ts create mode 100644 src/fp/object/omitBy.ts diff --git a/.scripts/fp/_internal/getter/functionDeclaration.ts b/.scripts/fp/_internal/getter/functionDeclaration.ts new file mode 100644 index 000000000..460eb27f7 --- /dev/null +++ b/.scripts/fp/_internal/getter/functionDeclaration.ts @@ -0,0 +1,42 @@ +import { + FunctionDeclaration, + Identifier, + JSCodeshift, + TSTypeAnnotation, + TSTypeParameterDeclaration, + TypeParameterDeclaration, +} from 'jscodeshift'; + +export function getFunctionDeclaration( + { + functionName, + typeParameters, + params, + returnType, + }: { + functionName: string; + typeParameters: TypeParameterDeclaration | TSTypeParameterDeclaration | null | undefined; + params: { + name: string[]; + type: TSTypeAnnotation[]; + }; + returnType: TSTypeAnnotation; + }, + j: JSCodeshift +) { + const newFunctionDeclaration = j.template.statement([ + `export function ${functionName}(${params.name.join(', ')});\n`, + ]) as { + declaration: Omit & { + params: Identifier[]; + }; + }; + + newFunctionDeclaration.declaration.typeParameters = typeParameters; + params.type.forEach((type, idx) => { + newFunctionDeclaration.declaration.params[idx].typeAnnotation = type; + }); + newFunctionDeclaration.declaration.returnType = returnType; + + return newFunctionDeclaration; +} diff --git a/.scripts/fp/_internal/getter/typedParam.ts b/.scripts/fp/_internal/getter/typedParam.ts new file mode 100644 index 000000000..64685319a --- /dev/null +++ b/.scripts/fp/_internal/getter/typedParam.ts @@ -0,0 +1,8 @@ +import { JSCodeshift } from 'jscodeshift'; +import { Param } from '../types'; + +export function getTypedParam({ name, type }: Param, j: JSCodeshift) { + const param = j.identifier(name); + param.typeAnnotation = j.tsTypeAnnotation(type); + return param; +} diff --git a/.scripts/fp/_internal/types.ts b/.scripts/fp/_internal/types.ts new file mode 100644 index 000000000..c1fb13951 --- /dev/null +++ b/.scripts/fp/_internal/types.ts @@ -0,0 +1,6 @@ +import { TSTypeKind } from 'ast-types/gen/kinds'; + +export type Param = { + name: string; + type: TSTypeKind; +}; diff --git a/.scripts/fp/_internal/validator/functionDeclaration.ts b/.scripts/fp/_internal/validator/functionDeclaration.ts new file mode 100644 index 000000000..fb957b71a --- /dev/null +++ b/.scripts/fp/_internal/validator/functionDeclaration.ts @@ -0,0 +1,15 @@ +import { Declaration, FunctionDeclaration, Identifier } from 'jscodeshift'; +import { namedTypes as n } from 'ast-types'; + +export function isValidFunctionDeclaration(functionDeclaration: Declaration | null): functionDeclaration is Omit< + FunctionDeclaration, + 'id' +> & { + id: Identifier; +} { + return ( + n.FunctionDeclaration.check(functionDeclaration) && + functionDeclaration.id != null && + n.TSTypeAnnotation.check(functionDeclaration.returnType) + ); +} diff --git a/.scripts/fp/_internal/validator/params.ts b/.scripts/fp/_internal/validator/params.ts new file mode 100644 index 000000000..7948808bf --- /dev/null +++ b/.scripts/fp/_internal/validator/params.ts @@ -0,0 +1,13 @@ +import { Identifier, Pattern, TSTypeAnnotation } from 'jscodeshift'; +import { namedTypes as n } from 'ast-types'; + +export function isValidParams( + params: Pattern[] +): params is (Omit & { typeAnnotation: TSTypeAnnotation })[] { + return params.every( + param => + n.Identifier.check(param) && + n.TSTypeAnnotation.check(param.typeAnnotation) && + !n.TSTypeAnnotation.check(param.typeAnnotation.typeAnnotation) + ); +} diff --git a/.scripts/fp/create-fp-version.sh b/.scripts/fp/create-fp-version.sh new file mode 100644 index 000000000..3b31aa062 --- /dev/null +++ b/.scripts/fp/create-fp-version.sh @@ -0,0 +1,6 @@ +FUNC=$1 + +find ./src -name "$1.ts" -maxdepth 2 -exec sh -c 'mkdir -p "./src/fp/$(dirname "{}" | sed "s|^./src/||")" && cp "{}" "./src/fp/$(dirname "{}" | sed "s|^./src/||")/"' \; +FP_FILENAME=$(find ./src/fp -name "$1.ts") +yarn jscodeshift -t ./.scripts/fp/toPipable.ts $FP_FILENAME +yarn prettier --write $FP_FILENAME \ No newline at end of file diff --git a/.scripts/fp/toPipable.ts b/.scripts/fp/toPipable.ts new file mode 100644 index 000000000..e83ab9d05 --- /dev/null +++ b/.scripts/fp/toPipable.ts @@ -0,0 +1,113 @@ +import { API, FileInfo, TSTypeAnnotation } from 'jscodeshift'; +import { TSTypeKind } from 'ast-types/gen/kinds'; +import { isValidFunctionDeclaration } from './_internal/validator/functionDeclaration'; +import { isValidParams } from './_internal/validator/params'; +import { Param } from './_internal/types'; +import { getTypedParam } from './_internal/getter/typedParam'; +import { getFunctionDeclaration } from './_internal/getter/functionDeclaration'; + +export const parser = 'tsx'; + +export default function transformer(file: FileInfo, api: API) { + const j = api.jscodeshift; + + return j(file.source) + .find(j.ExportNamedDeclaration) + .forEach(path => { + const functionDeclaration = path.value.declaration; + + if (!isValidFunctionDeclaration(functionDeclaration)) { + return; + } + + const functionName = functionDeclaration.id.name; + const functionBody = functionDeclaration.body; + + const params = functionDeclaration.params; + + if (!isValidParams(params)) { + return; + } + + const originParams: Record<'first' | 'second', Param> = { + first: { + name: params[0].name, + type: params[0].typeAnnotation.typeAnnotation as TSTypeKind, + }, + second: { + name: params[1].name, + type: params[1].typeAnnotation.typeAnnotation as TSTypeKind, + }, + }; + + const newFirstArgumentName = `${originParams.first.name}Or${originParams.second.name.replace(/./, first => first.toUpperCase())}`; + + const firstParam = getTypedParam(originParams.first, j); + + const selfCurringStatement = j.returnStatement( + j.arrowFunctionExpression( + [firstParam], + j.callExpression(j.identifier(functionName), [ + j.identifier(params[0].name), + j.tsAsExpression(j.identifier(newFirstArgumentName), originParams.second.type), + ]) + ) + ); + + const curringConditionalStatement = j.blockStatement([ + j.ifStatement( + j.binaryExpression('==', j.identifier(originParams.second.name), j.literal(null)), + j.blockStatement([selfCurringStatement]) + ), + j.variableDeclaration('const', [ + j.variableDeclarator( + j.identifier(params[0].name), + j.tsAsExpression(j.identifier(newFirstArgumentName), originParams.first.type) + ), + ]), + ]); + + params[0].name = newFirstArgumentName; + params[0].typeAnnotation = j.tsTypeAnnotation( + j.tsUnionType([originParams.first.type, originParams.second.type].map(j.tsParenthesizedType)) + ); + params[1].name = `${originParams.second.name}?`; + + functionDeclaration.body = j.blockStatement([...curringConditionalStatement.body, ...functionBody.body]); + + const nonCurriedDeclaration = getFunctionDeclaration( + { + functionName, + typeParameters: functionDeclaration.typeParameters, + params: { + name: [originParams.first.name, originParams.second.name], + type: [originParams.first.type, originParams.second.type].map(j.tsTypeAnnotation), + }, + returnType: functionDeclaration.returnType as TSTypeAnnotation, + }, + j + ); + + const returnOfCurried = j.tsFunctionType([getTypedParam(originParams.first, j)]); + returnOfCurried.typeAnnotation = functionDeclaration.returnType as TSTypeAnnotation; + + const curriedDeclaration = getFunctionDeclaration( + { + functionName, + typeParameters: functionDeclaration.typeParameters, + params: { + name: [originParams.second.name], + type: [j.tsTypeAnnotation(originParams.second.type)], + }, + returnType: j.tsTypeAnnotation(returnOfCurried), + }, + j + ); + + functionDeclaration.returnType = undefined; + + j(path).insertBefore(nonCurriedDeclaration); + j(path).insertBefore(curriedDeclaration); + }) + .toSource(); +} diff --git a/package.json b/package.json index 0c2b215e2..c10e1877b 100644 --- a/package.json +++ b/package.json @@ -143,6 +143,7 @@ "@types/node": "^20.12.11", "@types/tar": "^6.1.13", "@vitest/coverage-istanbul": "^1.5.2", + "ast-types": "^0.14.2", "broken-link-checker": "^0.7.8", "eslint": "^9.9.0", "eslint-config-prettier": "^9.1.0", @@ -169,6 +170,7 @@ "bench": "vitest bench", "lint": "eslint --config eslint.config.mjs", "format": "prettier --write .", - "transform": "jscodeshift -t ./.scripts/tests/transform-lodash-test.ts $0 && prettier --write $0" + "transform": "jscodeshift -t ./.scripts/tests/transform-lodash-test.ts $0 && prettier --write $0", + "fp": "sh ./.scripts/fp/create-fp-version.sh $0" } } diff --git a/src/fp/object/mapKeys.ts b/src/fp/object/mapKeys.ts new file mode 100644 index 000000000..cf3d58845 --- /dev/null +++ b/src/fp/object/mapKeys.ts @@ -0,0 +1,46 @@ +export function mapKeys( + object: T, + getNewKey: (value: T[K1], key: K1, object: T) => K2 +): Record; +export function mapKeys( + getNewKey: (value: T[K1], key: K1, object: T) => K2 +): (object: T) => Record; +/** + * Creates a new object with the same values as the given object, but with keys generated + * by running each own enumerable property of the object through the iteratee function. + * + * @template T - The type of the object. + * @template K1 - The type of the keys in the object. + * @template K2 - The type of the new keys generated by the iteratee function. + * + * @param {T} object - The object to iterate over. + * @param {(value: T[K1], key: K1, object: T) => K2} getNewKey - The function invoked per own enumerable property. + * @returns {Record} - Returns the new mapped object. + * + * @example + * // Example usage: + * const obj = { a: 1, b: 2 }; + * const result = mapKeys(obj, (value, key) => key + value); + * console.log(result); // { a1: 1, b2: 2 } + */ +export function mapKeys( + objectOrGetNewKey: T | ((value: T[K1], key: K1, object: T) => K2), + getNewKey?: (value: T[K1], key: K1, object: T) => K2 +) { + if (getNewKey == null) { + return (object: T) => mapKeys(object, objectOrGetNewKey as (value: T[K1], key: K1, object: T) => K2); + } + + const object = objectOrGetNewKey as T; + const result = {} as Record; + const keys = Object.keys(object); + + for (let i = 0; i < keys.length; i++) { + const key = keys[i] as K1; + const value = object[key]; + + result[getNewKey(value, key, object)] = value as any; + } + + return result; +} diff --git a/src/fp/object/omit.ts b/src/fp/object/omit.ts new file mode 100644 index 000000000..03c6cb0a3 --- /dev/null +++ b/src/fp/object/omit.ts @@ -0,0 +1,33 @@ +export function omit, K extends keyof T>(obj: T, keys: K[]): Omit; +export function omit, K extends keyof T>(keys: K[]): (obj: T) => Omit; +/** + * Creates a new object with specified keys omitted. + * + * This function takes an object and an array of keys, and returns a new object that + * excludes the properties corresponding to the specified keys. + * + * @template T - The type of object. + * @template K - The type of keys in object. + * @param {T} obj - The object to omit keys from. + * @param {K[]} keys - An array of keys to be omitted from the object. + * @returns {Omit} A new object with the specified keys omitted. + * + * @example + * const obj = { a: 1, b: 2, c: 3 }; + * const result = omit(obj, ['b', 'c']); + * // result will be { a: 1 } + */ +export function omit, K extends keyof T>(objOrKeys: T | K[], keys?: K[]) { + if (keys == null) { + return (obj: T) => omit(obj, objOrKeys as K[]); + } + + const obj = objOrKeys as T; + const result = { ...obj }; + + for (const key of keys) { + delete result[key]; + } + + return result as Omit; +} diff --git a/src/fp/object/omitBy.ts b/src/fp/object/omitBy.ts new file mode 100644 index 000000000..4c4eda92f --- /dev/null +++ b/src/fp/object/omitBy.ts @@ -0,0 +1,47 @@ +export function omitBy>( + obj: T, + shouldOmit: (value: T[keyof T], key: keyof T) => boolean +): Partial; +export function omitBy>( + shouldOmit: (value: T[keyof T], key: keyof T) => boolean +): (obj: T) => Partial; +/** + * Creates a new object composed of the properties that do not satisfy the predicate function. + * + * This function takes an object and a predicate function, and returns a new object that + * includes only the properties for which the predicate function returns false. + * + * @template T - The type of object. + * @param {T} obj - The object to omit properties from. + * @param {(value: T[string], key: keyof T) => boolean} shouldOmit - A predicate function that determines + * whether a property should be omitted. It takes the property's key and value as arguments and returns `true` + * if the property should be omitted, and `false` otherwise. + * @returns {Partial} A new object with the properties that do not satisfy the predicate function. + * + * @example + * const obj = { a: 1, b: 'omit', c: 3 }; + * const shouldOmit = (key, value) => typeof value === 'string'; + * const result = omitBy(obj, shouldOmit); + * // result will be { a: 1, c: 3 } + */ +export function omitBy>( + objOrShouldOmit: T | ((value: T[keyof T], key: keyof T) => boolean), + shouldOmit?: (value: T[keyof T], key: keyof T) => boolean +) { + if (shouldOmit == null) { + return (obj: T) => omitBy(obj, objOrShouldOmit as (value: T[keyof T], key: keyof T) => boolean); + } + + const obj = objOrShouldOmit as T; + const result: Partial = {}; + + for (const [key, value] of Object.entries(obj)) { + if (shouldOmit(value, key)) { + continue; + } + + (result as any)[key] = value; + } + + return result; +} diff --git a/yarn.lock b/yarn.lock index 28a109a64..5b7369d5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3596,7 +3596,7 @@ __metadata: languageName: node linkType: hard -"ast-types@npm:0.14.2, ast-types@npm:^0.14.1": +"ast-types@npm:0.14.2, ast-types@npm:^0.14.1, ast-types@npm:^0.14.2": version: 0.14.2 resolution: "ast-types@npm:0.14.2" dependencies: @@ -4923,6 +4923,7 @@ __metadata: "@types/node": "npm:^20.12.11" "@types/tar": "npm:^6.1.13" "@vitest/coverage-istanbul": "npm:^1.5.2" + ast-types: "npm:^0.14.2" broken-link-checker: "npm:^0.7.8" eslint: "npm:^9.9.0" eslint-config-prettier: "npm:^9.1.0" From 80e8f6506f64bb0c8a263d22989fd5dd7840b16f Mon Sep 17 00:00:00 2001 From: seungro Date: Sat, 2 Nov 2024 16:45:09 +0900 Subject: [PATCH 02/30] feat. add pipe --- src/fp/core/pipe.spec.ts | 44 ++++ src/fp/core/pipe.ts | 456 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 500 insertions(+) create mode 100644 src/fp/core/pipe.spec.ts create mode 100644 src/fp/core/pipe.ts diff --git a/src/fp/core/pipe.spec.ts b/src/fp/core/pipe.spec.ts new file mode 100644 index 000000000..4c54456f4 --- /dev/null +++ b/src/fp/core/pipe.spec.ts @@ -0,0 +1,44 @@ +import { describe, expect, expectTypeOf, it } from 'vitest'; +import { pipe } from './pipe'; + +describe('pipe', () => { + const isString = (value: unknown): value is string => typeof value === 'string'; + const toString = (value: unknown) => `string:${value}`; + const toStringAsync = (value: unknown) => + new Promise(resolve => setTimeout(() => resolve(`string:${value}`), 100)); + const length = (value: string) => value.length; + + it('should return value of the last function should be returned', () => { + expect(pipe(1, toString)).toBe('string:1'); + expect(pipe(true, toString)).toBe('string:true'); + expect(pipe(true, toString, isString)).toBe(true); + + expect(pipe(1, toString, length)).toBe(8); + expect(pipe(true, toString, length)).toBe(11); + expect(pipe(true, toString, length, isString)).toBe(false); + }); + + it('should return promise value if there is a function that returns a promise in the middle', async () => { + const promiseString = pipe(1, toStringAsync); + expect(promiseString).toBeInstanceOf(Promise); + expect(await promiseString).toBe('string:1'); + + const promiseLength = pipe(1, toStringAsync, length); + expect(promiseLength).toBeInstanceOf(Promise); + expect(await promiseLength).toBe(8); + + expectTypeOf(pipe(promiseString, isString)).toMatchTypeOf>(); + expectTypeOf(pipe(promiseLength, isString)).toMatchTypeOf>(); + }); + + it('should inference type correctly', () => { + expectTypeOf(pipe(1, toString)).toEqualTypeOf(); + expectTypeOf(pipe(1, toString, isString)).toEqualTypeOf(); + expectTypeOf(pipe(1, toString, length)).toEqualTypeOf(); + expectTypeOf(pipe(1, toString, length, isString)).toEqualTypeOf(); + expectTypeOf(pipe(1, toStringAsync)).toEqualTypeOf>(); + expectTypeOf(pipe(1, toStringAsync, length)).toEqualTypeOf>(); + expectTypeOf(pipe(1, toStringAsync, isString)).toMatchTypeOf>(); + expectTypeOf(pipe(1, toStringAsync, length, isString)).toMatchTypeOf>(); + }); +}); diff --git a/src/fp/core/pipe.ts b/src/fp/core/pipe.ts new file mode 100644 index 000000000..04abc951c --- /dev/null +++ b/src/fp/core/pipe.ts @@ -0,0 +1,456 @@ +type NextFunction = First extends true + ? (arg: T) => any + : T extends (args: any) => Promise + ? (arg: R) => any + : T extends (args: any) => any + ? (arg: ReturnType) => any + : never; + +type PipeResult = T extends [infer First, ...infer Last] + ? Promised extends true + ? PipeResult + : Initial extends true + ? First extends Promise + ? PipeResult + : PipeResult + : First extends (args: any) => infer R + ? R extends Promise + ? PipeResult + : PipeResult + : never + : Last extends (args: any) => infer R + ? R extends Promise + ? R + : Promised extends true + ? Promise + : R + : never; + +export function pipe>(initial: I, fn1: F1): PipeResult<[I, F1]>; +export function pipe, F2 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2 +): PipeResult<[I, F1, F2]>; +export function pipe, F2 extends NextFunction, F3 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3 +): PipeResult<[I, F1, F2, F3]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeResult<[I, F1, F2, F3, F4]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeResult<[I, F1, F2, F3, F4, F5]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeResult<[I, F1, F2, F3, F4, F5, F6]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, + F18 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17, + fn18: F18 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; + +export function pipe(initial: any, ...functions: Array<(arg: any) => any>): any { + return getNextFunction(initial, functions); +} + +function getNextFunction(prop: any, functions: Array<(arg: any) => any>) { + if (functions.length === 0) { + return prop; + } + + const [currentFunction, ...nextFunctions] = functions; + + if (prop instanceof Promise) { + prop.then(value => chainToNextFunction(value, currentFunction, nextFunctions)); + } + + return chainToNextFunction(prop, currentFunction, nextFunctions); +} + +function chainToNextFunction( + prop: any, + currentFunction: (arg: any) => any, + nextFunctions: Array<(arg: any) => any> +): any { + const returnValue = currentFunction(prop); + + if (returnValue instanceof Promise) { + return returnValue.then((value: any): any => getNextFunction(value, nextFunctions)); + } else { + return getNextFunction(returnValue, nextFunctions); + } +} From e8e280de46e72001daf6da0f77a47d5ad9060336 Mon Sep 17 00:00:00 2001 From: seungro Date: Sat, 2 Nov 2024 17:53:57 +0900 Subject: [PATCH 03/30] docs. add jsdoc --- src/fp/core/pipe.ts | 746 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 700 insertions(+), 46 deletions(-) diff --git a/src/fp/core/pipe.ts b/src/fp/core/pipe.ts index 04abc951c..e5b3a9d16 100644 --- a/src/fp/core/pipe.ts +++ b/src/fp/core/pipe.ts @@ -1,4 +1,4 @@ -type NextFunction = First extends true +type NextFunction = Type extends 'initial' ? (arg: T) => any : T extends (args: any) => Promise ? (arg: R) => any @@ -6,17 +6,17 @@ type NextFunction = First extends true ? (arg: ReturnType) => any : never; -type PipeResult = T extends [infer First, ...infer Last] +type PipeReturnType = T extends [infer First, ...infer Last] ? Promised extends true - ? PipeResult + ? PipeReturnType : Initial extends true ? First extends Promise - ? PipeResult - : PipeResult + ? PipeReturnType + : PipeReturnType : First extends (args: any) => infer R ? R extends Promise - ? PipeResult - : PipeResult + ? PipeReturnType + : PipeReturnType : never : Last extends (args: any) => infer R ? R extends Promise @@ -26,45 +26,259 @@ type PipeResult = T extends [in : R : never; -export function pipe>(initial: I, fn1: F1): PipeResult<[I, F1]>; -export function pipe, F2 extends NextFunction>( +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @returns {PipeReturnType<[I, F1]>} A processed value - return value of 1st function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * + * const result = pipe(1, toString); + * console.log(result); // 'string:1' + * + * const asyncResult = await pipe(1, toStringAsync); + * console.log(asyncResult); // 'string:1' + */ +export function pipe>(initial: I, fn1: F1): PipeReturnType<[I, F1]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @returns {PipeReturnType<[I, F1, F2]>} A processed value - return value of 2nd function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ +export function pipe, F2 extends NextFunction>( initial: I, fn1: F1, fn2: F2 -): PipeResult<[I, F1, F2]>; -export function pipe, F2 extends NextFunction, F3 extends NextFunction>( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3 -): PipeResult<[I, F1, F2, F3]>; +): PipeReturnType<[I, F1, F2]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3]>} A processed value - return value of 3rd function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ +export function pipe< + I, + F1 extends NextFunction, + F2 extends NextFunction, + F3 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3): PipeReturnType<[I, F1, F2, F3]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4]>} A processed value - return value of 4th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, ->(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeResult<[I, F1, F2, F3, F4]>; +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeReturnType<[I, F1, F2, F3, F4]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5]>} A processed value - return value of 5th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, F5 extends NextFunction, ->(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeResult<[I, F1, F2, F3, F4, F5]>; +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeReturnType<[I, F1, F2, F3, F4, F5]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>} A processed value - return value of 6th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, F5 extends NextFunction, F6 extends NextFunction, ->(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeResult<[I, F1, F2, F3, F4, F5, F6]>; +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>} A processed value - return value of 7th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -80,10 +294,45 @@ export function pipe< fn5: F5, fn6: F6, fn7: F7 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>} A processed value - return value of 8th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -101,10 +350,46 @@ export function pipe< fn6: F6, fn7: F7, fn8: F8 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>} A processed value - return value of 9th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -124,10 +409,47 @@ export function pipe< fn7: F7, fn8: F8, fn9: F9 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>} A processed value - return value of 10th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -149,10 +471,48 @@ export function pipe< fn8: F8, fn9: F9, fn10: F10 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>} A processed value - return value of 11th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -176,10 +536,49 @@ export function pipe< fn9: F9, fn10: F10, fn11: F11 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>} A processed value - return value of 12th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -205,10 +604,50 @@ export function pipe< fn10: F10, fn11: F11, fn12: F12 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>} A processed value - return value of 13th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -236,10 +675,51 @@ export function pipe< fn11: F11, fn12: F12, fn13: F13 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>} A processed value - return value of 14th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -269,10 +749,52 @@ export function pipe< fn12: F12, fn13: F13, fn14: F14 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>} A processed value - return value of 15th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -304,10 +826,53 @@ export function pipe< fn13: F13, fn14: F14, fn15: F15 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>} A processed value - return value of 16th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -341,10 +906,54 @@ export function pipe< fn14: F14, fn15: F15, fn16: F16 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>} A processed value - return value of 17th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -380,10 +989,55 @@ export function pipe< fn15: F15, fn16: F16, fn17: F17 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +/** + * Process a value through pipe. + * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. + * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, + * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. + * The pipe function can also handle async functions during the value processing. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. + * @param {F18 extends NextFunction} fn18 - 18th function that receives return value of 17th function as its parameter. + * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>} A processed value - return value of 18th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(1, toString, length); + * console.log(result); // 8 + * + * const asyncResult = await pipe(1, toStringAsync, length); + * console.log(asyncResult); // 8 + */ export function pipe< I, - F1 extends NextFunction, + F1 extends NextFunction, F2 extends NextFunction, F3 extends NextFunction, F4 extends NextFunction, @@ -421,7 +1075,7 @@ export function pipe< fn16: F16, fn17: F17, fn18: F18 -): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; +): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; export function pipe(initial: any, ...functions: Array<(arg: any) => any>): any { return getNextFunction(initial, functions); From 4d889d153dce6808365068f8a643b6591b6443ae Mon Sep 17 00:00:00 2001 From: seungro Date: Sat, 2 Nov 2024 22:18:27 +0900 Subject: [PATCH 04/30] docs. add docs about pipe --- docs/.vitepress/en.mts | 9 + docs/.vitepress/ja.mts | 9 + docs/.vitepress/ko.mts | 9 + docs/.vitepress/libs/getSidebarItems.mts | 20 + docs/.vitepress/theme/index.css | 4 + docs/.vitepress/zh_hans.mts | 9 + docs/ja/reference/fp/function/pipe.md | 447 +++++++++++++++++++++ docs/ko/reference/fp/function/pipe.md | 447 +++++++++++++++++++++ docs/reference/fp/function/pipe.md | 447 +++++++++++++++++++++ docs/zh_hans/reference/fp/function/pipe.md | 447 +++++++++++++++++++++ src/fp/core/pipe.ts | 410 ++++++++++++++----- 11 files changed, 2152 insertions(+), 106 deletions(-) create mode 100644 docs/ja/reference/fp/function/pipe.md create mode 100644 docs/ko/reference/fp/function/pipe.md create mode 100644 docs/reference/fp/function/pipe.md create mode 100644 docs/zh_hans/reference/fp/function/pipe.md diff --git a/docs/.vitepress/en.mts b/docs/.vitepress/en.mts index cbc5602fd..ce3c22665 100644 --- a/docs/.vitepress/en.mts +++ b/docs/.vitepress/en.mts @@ -55,6 +55,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'array'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'array'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'array'), ], }, { @@ -62,6 +63,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'function'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'function'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'function'), ], }, { @@ -69,6 +71,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'math'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'math'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'math'), ], }, { @@ -76,6 +79,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'object'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'object'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'object'), ], }, { @@ -83,6 +87,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'predicate'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'predicate'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'predicate'), ], }, { @@ -90,6 +95,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'promise'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'promise'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'promise'), ], }, { @@ -97,6 +103,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'string'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'string'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'string'), ], }, { @@ -104,6 +111,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'util'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'util'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'util'), ], }, { @@ -111,6 +119,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'reference', 'error'), ...getSidebarItems.compat('en', docsRoot, 'reference', 'compat', 'error'), + ...getSidebarItems.fp('en', docsRoot, 'reference', 'fp', 'error'), ], }, ]), diff --git a/docs/.vitepress/ja.mts b/docs/.vitepress/ja.mts index 95cd3f935..31491588c 100644 --- a/docs/.vitepress/ja.mts +++ b/docs/.vitepress/ja.mts @@ -54,6 +54,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'array'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'array'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'array'), ], }, { @@ -61,6 +62,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'function'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'function'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'function'), ], }, { @@ -68,6 +70,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'math'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'math'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'math'), ], }, { @@ -75,6 +78,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'object'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'object'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'object'), ], }, { @@ -82,6 +86,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'predicate'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'predicate'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'predicate'), ], }, { @@ -89,6 +94,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'promise'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'promise'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'promise'), ], }, { @@ -96,6 +102,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'string'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'string'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'string'), ], }, { @@ -103,6 +110,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'util'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'util'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'util'), ], }, { @@ -110,6 +118,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ja', 'reference', 'error'), ...getSidebarItems.compat('ja', docsRoot, 'ja', 'reference', 'compat', 'error'), + ...getSidebarItems.fp('ja', docsRoot, 'ja', 'reference', 'fp', 'error'), ], }, ]), diff --git a/docs/.vitepress/ko.mts b/docs/.vitepress/ko.mts index 2db47d5a9..7525ace21 100644 --- a/docs/.vitepress/ko.mts +++ b/docs/.vitepress/ko.mts @@ -54,6 +54,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'array'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'array'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'array'), ], }, { @@ -61,6 +62,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'function'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'function'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'function'), ], }, { @@ -68,6 +70,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'math'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'math'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'math'), ], }, { @@ -75,6 +78,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'object'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'object'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'object'), ], }, { @@ -82,6 +86,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'predicate'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'predicate'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'predicate'), ], }, { @@ -89,6 +94,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'promise'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'promise'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'array'), ], }, { @@ -96,6 +102,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'string'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'string'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'string'), ], }, { @@ -103,6 +110,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'util'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'util'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'util'), ], }, { @@ -110,6 +118,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'ko', 'reference', 'error'), ...getSidebarItems.compat('ko', docsRoot, 'ko', 'reference', 'compat', 'error'), + ...getSidebarItems.fp('ko', docsRoot, 'ko', 'reference', 'fp', 'error'), ], }, ]), diff --git a/docs/.vitepress/libs/getSidebarItems.mts b/docs/.vitepress/libs/getSidebarItems.mts index a5c78f1d5..ebe9be69d 100644 --- a/docs/.vitepress/libs/getSidebarItems.mts +++ b/docs/.vitepress/libs/getSidebarItems.mts @@ -35,3 +35,23 @@ getSidebarItems.compat = function (locale: 'en' | 'ko' | 'ja' | 'zh_hans', docsR }; }); }; + +getSidebarItems.fp = function (locale: 'en' | 'ko' | 'ja' | 'zh_hans', docsRoot: string, ...paths: string[]) { + return getSidebarItems(docsRoot, ...paths).map(item => { + const compatStr = + locale === 'en' + ? '(fp)' + : locale === 'ko' + ? '(함수형)' + : locale === 'ja' + ? '(関数型プログラミング)' + : locale === 'zh_hans' + ? '(函数式编程)' + : ''; + + return { + ...item, + text: `${item.text} ${compatStr}`, + }; + }); +}; diff --git a/docs/.vitepress/theme/index.css b/docs/.vitepress/theme/index.css index 55d7a65b0..1504cf1eb 100644 --- a/docs/.vitepress/theme/index.css +++ b/docs/.vitepress/theme/index.css @@ -7,3 +7,7 @@ :root[lang='ko'] { word-break: keep-all; } + +#signature + div > pre.vp-code { + max-height: 500px; +} diff --git a/docs/.vitepress/zh_hans.mts b/docs/.vitepress/zh_hans.mts index 2443936ef..8b2a623db 100644 --- a/docs/.vitepress/zh_hans.mts +++ b/docs/.vitepress/zh_hans.mts @@ -55,6 +55,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'array'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'array'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'array'), ], }, { @@ -62,6 +63,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'function'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'function'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'function'), ], }, { @@ -69,6 +71,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'math'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'math'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'math'), ], }, { @@ -76,6 +79,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'object'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'object'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'object'), ], }, { @@ -83,6 +87,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'predicate'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'predicate'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'predicate'), ], }, { @@ -90,6 +95,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'promise'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'promise'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'promise'), ], }, { @@ -97,6 +103,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'string'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'string'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'string'), ], }, { @@ -104,6 +111,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'util'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'util'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'util'), ], }, { @@ -111,6 +119,7 @@ function sidebar(): DefaultTheme.Sidebar { items: [ ...getSidebarItems(docsRoot, 'zh_hans', 'reference', 'error'), ...getSidebarItems.compat('zh_hans', docsRoot, 'zh_hans', 'reference', 'compat', 'error'), + ...getSidebarItems.fp('zh_hans', docsRoot, 'zh_hans', 'reference', 'fp', 'error'), ], }, ]), diff --git a/docs/ja/reference/fp/function/pipe.md b/docs/ja/reference/fp/function/pipe.md new file mode 100644 index 000000000..bda9e4062 --- /dev/null +++ b/docs/ja/reference/fp/function/pipe.md @@ -0,0 +1,447 @@ +# pipe + +パイプを通過しながら値を処理します。複数のステップで値を加工するコードを宣言的に記述する際に便利です。 + +加工したい初期値を `pipe` 関数に第一引数として渡し、第二引数以降には値を加工する関数を順番に渡してください。こうすることで、`pipe` 関数の最初の関数は初期値をパラメータとして受け取り、残りの関数は前の関数が返す値を受け取って順番に実行され、最後の関数まで実行されます。 + +もし初期値が Promise の値であったり、値を処理する過程で非同期関数が存在する場合、`pipe` 関数は値を非同期的に処理して `Promise` を返します。 + +## インターフェース + +```typescript +export function pipe>(initial: I, fn1: F1): PipeResult<[I, F1]>; +export function pipe, F2 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2 +): PipeResult<[I, F1, F2]>; +export function pipe, F2 extends NextFunction, F3 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3 +): PipeResult<[I, F1, F2, F3]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeResult<[I, F1, F2, F3, F4]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeResult<[I, F1, F2, F3, F4, F5]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeResult<[I, F1, F2, F3, F4, F5, F6]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, + F18 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17, + fn18: F18 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; +``` + +### パラメータ + +- `initial` (`I`): 処理される初期値です。 +- `fn1 ~ fn` (`F1 ~ F{n}`): 順番に値を処理する関数たちです。各関数は前の関数の返り値をパラメータとして受け取って実行されます。関数は最大で18個まで渡すことができます。 + +## 戻り値 + +(`PipeResult`): 処理された結果値、つまり最後の関数の返り値です。もし初期値が `Promise` であったり、中間に非同期関数がある場合、`pipe` 関数は `Promise` の値を返します。 + +## 例 + +```typescript +function toString(value: unknown) { + return `string:${value}`; +} + +function toStringAsync(value: unknown) { + return Promise.resolve(`string:${value}`); +} + +function length(value: string) { + return value.length; +} + +const result = pipe(1, toString, length); +console.log(result); // 8 + +// 非同期関数と一緒に使用できます。 +const asyncResult = await pipe(1, toStringAsync, length); +console.log(asyncResult); // 8 + +// `curry` 化された関数と一緒に使用できます。 +const mapKeyResult = await pipe( + { a: 1, b: 2 }, + mapKeys((value, key) => key + value) +); +console.log(mapKeyResult); // { a1: 1, b2: 2 } +``` diff --git a/docs/ko/reference/fp/function/pipe.md b/docs/ko/reference/fp/function/pipe.md new file mode 100644 index 000000000..f8aaed28b --- /dev/null +++ b/docs/ko/reference/fp/function/pipe.md @@ -0,0 +1,447 @@ +# pipe + +파이프를 통과하면서 값을 처리해요. 여러 단계에 걸쳐 값을 가공하는 코드를 선언적으로 작성할 때 유용해요. + +가공하고자 하는 초기값을 `pipe` 함수에 첫번째 인자값으로 전달하고, 두번째부터는 값을 가공할 함수를 순서대로 전달하세요. 이렇게 하면 `pipe` 함첫 번째 함수는 초기값을 파라미터로 받고, 나머지 함수들은 앞선 함수가 반환하는 값을 받아 순서대로 실행되는 형태로 마지막 함수까지 실행할 수 있어요. + +만약 초기값이 `Promise` 값이거나, 값을 처리하는 과정에서 비동기 함수가 존재하면, `pipe` 함수가 값을 비동기적으로 처리해서 `Promise`를 반환해요. + +## 인터페이스 + +```typescript +export function pipe>(initial: I, fn1: F1): PipeResult<[I, F1]>; +export function pipe, F2 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2 +): PipeResult<[I, F1, F2]>; +export function pipe, F2 extends NextFunction, F3 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3 +): PipeResult<[I, F1, F2, F3]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeResult<[I, F1, F2, F3, F4]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeResult<[I, F1, F2, F3, F4, F5]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeResult<[I, F1, F2, F3, F4, F5, F6]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, + F18 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17, + fn18: F18 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; +``` + +### 파라미터 + +- `initial` (`I`): 처리될 초기 값이에요. +- `fn1 ~ fn` (`F1 ~ F{n}`): 순서대로 값을 처리할 함수들이에요. 각 함수는 이전 함수의 반환값을 파라미터로 전달 받아 실행돼요. 함수들은 최대 18개까지 전달할 수 있어요. + +## 반환 값 + +(`PipeResult`): 처리된 결과 값, 즉 마지막 함수의 반환값이에요. 만약 초기 값이 `Promise`이거나 중간에 비동기 함수가 있다면, `pipe` 함수는 `Promise` 값을 반환해요. + +## 예시 + +```typescript +function toString(value: unknown) { + return `string:${value}`; +} + +function toStringAsync(value: unknown) { + return Promise.resolve(`string:${value}`); +} + +function length(value: string) { + return value.length; +} + +const result = pipe(1, toString, length); +console.log(result); // 8 + +// 비동기 함수와 함께 사용할 수 있어요. +const asyncResult = await pipe(1, toStringAsync, length); +console.log(asyncResult); // 8 + +// 커링된 함수와 함께 사용할 수 있어요. +const mapKeyResult = await pipe( + { a: 1, b: 2 }, + mapKeys((value, key) => key + value) +); +console.log(mapKeyResult); // { a1: 1, b2: 2 } +``` diff --git a/docs/reference/fp/function/pipe.md b/docs/reference/fp/function/pipe.md new file mode 100644 index 000000000..d845cf65b --- /dev/null +++ b/docs/reference/fp/function/pipe.md @@ -0,0 +1,447 @@ +# pipe + +Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + +Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + +If the initial value is a `Promise` or if there are async functions in the processing chain, the `pipe` function will handle the value asynchronously and return a `Promise`. + +## Signature + +```typescript +export function pipe>(initial: I, fn1: F1): PipeResult<[I, F1]>; +export function pipe, F2 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2 +): PipeResult<[I, F1, F2]>; +export function pipe, F2 extends NextFunction, F3 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3 +): PipeResult<[I, F1, F2, F3]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeResult<[I, F1, F2, F3, F4]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeResult<[I, F1, F2, F3, F4, F5]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeResult<[I, F1, F2, F3, F4, F5, F6]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, + F18 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17, + fn18: F18 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; +``` + +### Parameters + +- `initial` (`I`): The initial value to be processed. +- `fn1 ~ fn` (`F1 ~ F{n}`): The functions that are called in order during the value processing. Each function receives the return value of the previous function as its parameter. the maximum number of functions is 18 + +## Returns + +(`PipeResult`): Processed result value, specifically the return value of the last function. If the initial value is a `Promise` or if there are async functions in the middle, the `pipe` function will return a `Promise` value. + +## Examples + +```typescript +function toString(value: unknown) { + return `string:${value}`; +} + +function toStringAsync(value: unknown) { + return Promise.resolve(`string:${value}`); +} + +function length(value: string) { + return value.length; +} + +const result = pipe(1, toString, length); +console.log(result); // 8 + +// Use pipe with async function +const asyncResult = await pipe(1, toStringAsync, length); +console.log(asyncResult); // 8 + +// Use pipe with curried function +const mapKeyResult = await pipe( + { a: 1, b: 2 }, + mapKeys((value, key) => key + value) +); +console.log(mapKeyResult); // { a1: 1, b2: 2 } +``` diff --git a/docs/zh_hans/reference/fp/function/pipe.md b/docs/zh_hans/reference/fp/function/pipe.md new file mode 100644 index 000000000..07300f4d9 --- /dev/null +++ b/docs/zh_hans/reference/fp/function/pipe.md @@ -0,0 +1,447 @@ +# pipe + +通过管道处理值。在以声明性方式编写对值进行多步骤加工的代码时非常有用。 + +将要加工的初始值作为第一个参数传递给 `pipe` 函数,从第二个参数开始按顺序传递要加工的函数。这样,`pipe` 函数的第一个函数将接收初始值作为参数,其余函数将接收前一个函数返回的值,并按顺序执行,直到最后一个函数。 + +如果初始值是 `Promise` 值,或者在处理过程中存在异步函数,`pipe` 函数将异步处理值并返回 `Promise`。 + +## 签名 + +```typescript +export function pipe>(initial: I, fn1: F1): PipeResult<[I, F1]>; +export function pipe, F2 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2 +): PipeResult<[I, F1, F2]>; +export function pipe, F2 extends NextFunction, F3 extends NextFunction>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3 +): PipeResult<[I, F1, F2, F3]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeResult<[I, F1, F2, F3, F4]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeResult<[I, F1, F2, F3, F4, F5]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, +>(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeResult<[I, F1, F2, F3, F4, F5, F6]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +export function pipe< + I, + F1 extends NextFuntion, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, + F18 extends NextFunction, +>( + initial: I, + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17, + fn18: F18 +): PipeResult<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; +``` + +### 파라미터 + +- `initial` (`I`): 处理的初始值。 +- `fn1 ~ fn` (`F1 ~ F{n}`): 顺序处理值的函数。每个函数接收前一个函数的返回值作为参数执行。最多可以传递 18 个函数。 + +## 반환 값 + +(`PipeResult`): 处理后的结果值,即最后一个函数的返回值。如果初始值是 `Promise` 或者中间有异步函数,那么 `pipe` 函数将返回 `Promise` 值。 + +## 예시 + +```typescript +function toString(value: unknown) { + return `string:${value}`; +} + +function toStringAsync(value: unknown) { + return Promise.resolve(`string:${value}`); +} + +function length(value: string) { + return value.length; +} + +const result = pipe(1, toString, length); +console.log(result); // 8 + +// 可以与异步函数一起使用。 +const asyncResult = await pipe(1, toStringAsync, length); +console.log(asyncResult); // 8 + +// 可以与 `curry` 化的函数一起使用。 +const mapKeyResult = await pipe( + { a: 1, b: 2 }, + mapKeys((value, key) => key + value) +); +console.log(mapKeyResult); // { a1: 1, b2: 2 } +``` diff --git a/src/fp/core/pipe.ts b/src/fp/core/pipe.ts index e5b3a9d16..06f87cca1 100644 --- a/src/fp/core/pipe.ts +++ b/src/fp/core/pipe.ts @@ -27,11 +27,14 @@ type PipeReturnType = T extends : never; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -48,16 +51,27 @@ type PipeReturnType = T extends * const result = pipe(1, toString); * console.log(result); // 'string:1' * + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync); * console.log(asyncResult); // 'string:1' + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe>(initial: I, fn1: F1): PipeReturnType<[I, F1]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -77,9 +91,17 @@ export function pipe>(initial: I, fn1: * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe, F2 extends NextFunction>( initial: I, @@ -87,11 +109,14 @@ export function pipe, F2 extends NextFu fn2: F2 ): PipeReturnType<[I, F1, F2]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -112,9 +137,17 @@ export function pipe, F2 extends NextFu * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -123,11 +156,14 @@ export function pipe< F3 extends NextFunction, >(initial: I, fn1: F1, fn2: F2, fn3: F3): PipeReturnType<[I, F1, F2, F3]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -149,9 +185,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -161,11 +205,14 @@ export function pipe< F4 extends NextFunction, >(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeReturnType<[I, F1, F2, F3, F4]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -189,8 +236,16 @@ export function pipe< * const result = pipe(1, toString, length); * console.log(result); // 8 * + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -201,11 +256,14 @@ export function pipe< F5 extends NextFunction, >(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeReturnType<[I, F1, F2, F3, F4, F5]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -229,9 +287,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -243,11 +309,14 @@ export function pipe< F6 extends NextFunction, >(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -272,9 +341,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -296,11 +373,14 @@ export function pipe< fn7: F7 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -326,9 +406,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -352,11 +440,14 @@ export function pipe< fn8: F8 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -383,9 +474,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -411,11 +510,14 @@ export function pipe< fn9: F9 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -443,9 +545,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -473,11 +583,14 @@ export function pipe< fn10: F10 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -506,9 +619,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -538,11 +659,14 @@ export function pipe< fn11: F11 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -572,9 +696,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -606,11 +738,14 @@ export function pipe< fn12: F12 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -641,9 +776,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -677,11 +820,14 @@ export function pipe< fn13: F13 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -713,9 +859,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -751,11 +905,14 @@ export function pipe< fn14: F14 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -788,9 +945,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -828,11 +993,14 @@ export function pipe< fn15: F15 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -866,9 +1034,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -908,11 +1084,14 @@ export function pipe< fn16: F16 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -947,9 +1126,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, @@ -991,11 +1178,14 @@ export function pipe< fn17: F17 ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; /** - * Process a value through pipe. - * The first parameter of the `pipe` function is the initial value, and from the second parameter onward, it receives functions. - * The first function receives the initial value as its parameter, while each subsequent function receives the return value of the previous function as its parameter, - * executing all the way to the last function. Ultimately, the pipe function returns the return value of the last function. - * The pipe function can also handle async functions during the value processing. + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, + * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, + * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. + * + * If the initial value is a `Promise` or if there are async functions in the processing chain, + * the `pipe` function will handle the value asynchronously and return a `Promise`. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -1031,9 +1221,17 @@ export function pipe< * * const result = pipe(1, toString, length); * console.log(result); // 8 - * + + * // Use pipe with async function * const asyncResult = await pipe(1, toStringAsync, length); * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const mapKeyResult = await pipe( + * { a: 1, b: 2 }, + * mapKeys((value, key) => key + value) + * ); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< I, From fe29594864ad0d037d1f20c3e5413637fc6a47e5 Mon Sep 17 00:00:00 2001 From: seungro Date: Sat, 2 Nov 2024 23:00:54 +0900 Subject: [PATCH 05/30] chore. configs for fp --- .attw.json | 1 + .scripts/docs/generate-docs.mts | 8 ++++++++ .scripts/docs/operations/render/en.ts | 24 +++++++++++++++------- .scripts/docs/operations/render/ja.ts | 24 +++++++++++++++------- .scripts/docs/operations/render/ko.ts | 24 +++++++++++++++------- .scripts/docs/operations/render/types.ts | 1 + .scripts/docs/operations/render/zh_hans.ts | 24 +++++++++++++++------- .scripts/postbuild.sh | 1 + docs/.vitepress/libs/getSidebarItems.mts | 4 ++-- docs/ja/reference/fp/function/pipe.md | 6 ++++++ docs/ko/reference/fp/function/pipe.md | 6 ++++++ docs/reference/fp/function/pipe.md | 6 ++++++ docs/zh_hans/reference/fp/function/pipe.md | 6 ++++++ jsr.json | 3 ++- package.json | 11 ++++++++++ src/fp/index.ts | 6 ++++++ tests/check-dist.spec.ts | 1 + vitest.config.mts | 2 +- 18 files changed, 126 insertions(+), 32 deletions(-) create mode 100644 src/fp/index.ts diff --git a/.attw.json b/.attw.json index 068bad353..2112aa6a5 100644 --- a/.attw.json +++ b/.attw.json @@ -4,6 +4,7 @@ "includeEntrypoints": [ "array", "compat", + "fp", "function", "math", "object", diff --git a/.scripts/docs/generate-docs.mts b/.scripts/docs/generate-docs.mts index dbda636e6..95f4b273b 100644 --- a/.scripts/docs/generate-docs.mts +++ b/.scripts/docs/generate-docs.mts @@ -48,6 +48,14 @@ async function run() { ); await renderDocs(docsPaths, compatItems, { compat: true }); + + const fpItems = differenceWith( + toDocumentationItems(await doc(`file:${path.join(basePath, 'fp', 'index.ts')}`)), + items, + (x, y) => x.item.name === y.item.name + ); + + await renderDocs(docsPaths, fpItems, { fp: true }); } async function renderDocs(docsPaths: DocumentationPaths, items: DocumentationItems, options: RenderOptions = {}) { diff --git a/.scripts/docs/operations/render/en.ts b/.scripts/docs/operations/render/en.ts index 9e74cea77..e2e0dce35 100644 --- a/.scripts/docs/operations/render/en.ts +++ b/.scripts/docs/operations/render/en.ts @@ -2,7 +2,7 @@ import { RenderOptions } from './types.ts'; import { DocumentationItem } from '../../types/DocumentationItem.ts'; export function render(item: DocumentationItem, options: RenderOptions = {}) { - return [title(item.name), compatNotice(options), item.description, signature(item), examples(item)] + return [title(item.name), getNotice(options), item.description, signature(item), examples(item)] .filter(x => x != null) .join('\n\n'); } @@ -11,18 +11,28 @@ function title(name: string) { return `# ${name}`; } -function compatNotice(options: RenderOptions) { - if (!options.compat) { - return null; - } - - return ` +function getNotice(options: RenderOptions) { + if (options.compat) { + return ` ::: info This function is only available in \`es-toolkit/compat\` for compatibility reasons. It either has alternative native JavaScript APIs or isn’t fully optimized yet. When imported from \`es-toolkit/compat\`, it behaves exactly like lodash and provides the same functionalities, as detailed [here](../../../compatibility.md). ::: `.trim(); + } + + if (options.fp) { + return ` +::: info +This function can only be imported from \`es-toolkit/fp\`, which supports writing code in a functional programming style. + +When import code from \`es-toolkit/fp\`, you can use the pipe syntax or functions that automatically curry based on the number of input arguments. +::: +`.trim(); + } + + return null; } function signature(item: DocumentationItem) { diff --git a/.scripts/docs/operations/render/ja.ts b/.scripts/docs/operations/render/ja.ts index c9fc93518..7730a8174 100644 --- a/.scripts/docs/operations/render/ja.ts +++ b/.scripts/docs/operations/render/ja.ts @@ -2,7 +2,7 @@ import { RenderOptions } from './types.ts'; import { DocumentationItem } from '../../types/DocumentationItem.ts'; export function render(item: DocumentationItem, options: RenderOptions = {}) { - return [title(item.name), compatNotice(options), item.description, signature(item), examples(item)] + return [title(item.name), getNotice(options), item.description, signature(item), examples(item)] .filter(x => x != null) .join('\n\n'); } @@ -11,18 +11,28 @@ function title(name: string) { return `# ${name}`; } -function compatNotice(options: RenderOptions) { - if (!options.compat) { - return null; - } - - return ` +function getNotice(options: RenderOptions) { + if (options.compat) { + return ` ::: info この関数は互換性のために \`es-toolkit/compat\` からのみインポートできます。代替可能なネイティブ JavaScript API があるか、まだ十分に最適化されていないためです。 \`es-toolkit/compat\` からこの関数をインポートすると、[lodash と完全に同じように動作](../../../compatibility.md)します。 ::: `.trim(); + } + + if (options.fp) { + return ` +::: info +この関数は関数型プログラミングスタイルのコードを書くために \`es-toolkit/fp\` からのみインポートできます。 + +\`es-toolkit/fp\` から関数をインポートすると、パイプ文法を使用したり、引数の数に応じて自動的に curry 化される関数を使用することができます。 +::: +`.trim(); + } + + return null; } function signature(item: DocumentationItem) { diff --git a/.scripts/docs/operations/render/ko.ts b/.scripts/docs/operations/render/ko.ts index 2de4384f8..197d61313 100644 --- a/.scripts/docs/operations/render/ko.ts +++ b/.scripts/docs/operations/render/ko.ts @@ -2,7 +2,7 @@ import { RenderOptions } from './types.ts'; import { DocumentationItem } from '../../types/DocumentationItem.ts'; export function render(item: DocumentationItem, options: RenderOptions = {}) { - return [title(item.name), compatNotice(options), item.description, signature(item), examples(item)] + return [title(item.name), getNotice(options), item.description, signature(item), examples(item)] .filter(x => x != null) .join('\n\n'); } @@ -11,18 +11,28 @@ function title(name: string) { return `# ${name}`; } -function compatNotice(options: RenderOptions) { - if (!options.compat) { - return null; - } - - return ` +function getNotice(options: RenderOptions) { + if (options.compat) { + return ` ::: info 이 함수는 호환성을 위한 \`es-toolkit/compat\` 에서만 가져올 수 있어요. 대체할 수 있는 네이티브 JavaScript API가 있거나, 아직 충분히 최적화되지 않았기 때문이에요. \`es-toolkit/compat\`에서 이 함수를 가져오면, [lodash와 완전히 똑같이 동작](../../../compatibility.md)해요. ::: `.trim(); + } + + if (options.fp) { + return ` +::: info +이 함수는 함수형 프로그래밍 방식의 코드 작성을 지원하기 위한 \`es-toolkit/fp\` 에서만 가져올 수 있어요. + +\`es-toolkit/fp\`에서 함수를 가져오면 pipe 문법을 사용하거나 인자 입력 갯수에 따라 자동으로 커링되는 함수를 사용할 수 있어요. +::: +`.trim(); + } + + return null; } function signature(item: DocumentationItem) { diff --git a/.scripts/docs/operations/render/types.ts b/.scripts/docs/operations/render/types.ts index cb727ae28..c30fa415a 100644 --- a/.scripts/docs/operations/render/types.ts +++ b/.scripts/docs/operations/render/types.ts @@ -1,3 +1,4 @@ export interface RenderOptions { compat?: boolean; + fp?: boolean; } diff --git a/.scripts/docs/operations/render/zh_hans.ts b/.scripts/docs/operations/render/zh_hans.ts index f388effcf..5e00647d7 100644 --- a/.scripts/docs/operations/render/zh_hans.ts +++ b/.scripts/docs/operations/render/zh_hans.ts @@ -2,7 +2,7 @@ import { RenderOptions } from './types.ts'; import { DocumentationItem } from '../../types/DocumentationItem.ts'; export function render(item: DocumentationItem, options: RenderOptions = {}) { - return [title(item.name), compatNotice(options), item.description, signature(item), examples(item)] + return [title(item.name), getNotice(options), item.description, signature(item), examples(item)] .filter(x => x != null) .join('\n\n'); } @@ -11,18 +11,28 @@ function title(name: string) { return `# ${name}`; } -function compatNotice(options: RenderOptions) { - if (!options.compat) { - return null; - } - - return ` +function getNotice(options: RenderOptions) { + if (options.compat) { + return ` ::: info 出于兼容性原因,此函数仅在 \`es-toolkit/compat\` 中提供。它可能具有替代的原生 JavaScript API,或者尚未完全优化。 从 \`es-toolkit/compat\` 导入时,它的行为与 lodash 完全一致,并提供相同的功能,详情请见 [这里](../../../compatibility.md)。 ::: `.trim(); + } + + if (options.fp) { + return ` +::: info +这个函数只能从 \`es-toolkit/fp\` 导入,以支持函数式编程风格的代码编写。 + +从 \`es-toolkit/fp\` 导入函数后,可以使用管道语法或根据输入参数数量自动 curry 化的函数。 +::: +`.trim(); + } + + return null; } function signature(item: DocumentationItem) { diff --git a/.scripts/postbuild.sh b/.scripts/postbuild.sh index 815dd9f85..066f821ac 100755 --- a/.scripts/postbuild.sh +++ b/.scripts/postbuild.sh @@ -5,6 +5,7 @@ # (which is the default when using "module": "commonjs"). echo "export * from './dist/array';" > array.d.ts echo "export * from './dist/compat';" > compat.d.ts +echo "export * from './dist/fp';" > fp.d.ts echo "export * from './dist/function';" > function.d.ts echo "export * from './dist/math';" > math.d.ts echo "export * from './dist/object';" > object.d.ts diff --git a/docs/.vitepress/libs/getSidebarItems.mts b/docs/.vitepress/libs/getSidebarItems.mts index ebe9be69d..a7328a819 100644 --- a/docs/.vitepress/libs/getSidebarItems.mts +++ b/docs/.vitepress/libs/getSidebarItems.mts @@ -38,7 +38,7 @@ getSidebarItems.compat = function (locale: 'en' | 'ko' | 'ja' | 'zh_hans', docsR getSidebarItems.fp = function (locale: 'en' | 'ko' | 'ja' | 'zh_hans', docsRoot: string, ...paths: string[]) { return getSidebarItems(docsRoot, ...paths).map(item => { - const compatStr = + const fpStr = locale === 'en' ? '(fp)' : locale === 'ko' @@ -51,7 +51,7 @@ getSidebarItems.fp = function (locale: 'en' | 'ko' | 'ja' | 'zh_hans', docsRoot: return { ...item, - text: `${item.text} ${compatStr}`, + text: `${item.text} ${fpStr}`, }; }); }; diff --git a/docs/ja/reference/fp/function/pipe.md b/docs/ja/reference/fp/function/pipe.md index bda9e4062..f0eec2196 100644 --- a/docs/ja/reference/fp/function/pipe.md +++ b/docs/ja/reference/fp/function/pipe.md @@ -1,5 +1,11 @@ # pipe +::: info +この関数は関数型プログラミングスタイルのコードを書くために `es-toolkit/fp` からのみインポートできます。 + +`es-toolkit/fp` から関数をインポートすると、パイプ文法を使用したり、引数の数に応じて自動的に curry 化される関数を使用することができます。 +::: + パイプを通過しながら値を処理します。複数のステップで値を加工するコードを宣言的に記述する際に便利です。 加工したい初期値を `pipe` 関数に第一引数として渡し、第二引数以降には値を加工する関数を順番に渡してください。こうすることで、`pipe` 関数の最初の関数は初期値をパラメータとして受け取り、残りの関数は前の関数が返す値を受け取って順番に実行され、最後の関数まで実行されます。 diff --git a/docs/ko/reference/fp/function/pipe.md b/docs/ko/reference/fp/function/pipe.md index f8aaed28b..d6f264b71 100644 --- a/docs/ko/reference/fp/function/pipe.md +++ b/docs/ko/reference/fp/function/pipe.md @@ -1,5 +1,11 @@ # pipe +::: info +이 함수는 함수형 프로그래밍 방식의 코드 작성을 지원하기 위한 `es-toolkit/fp` 에서만 가져올 수 있어요. + +`es-toolkit/fp`에서 함수를 가져오면 pipe 문법을 사용하거나 인자 입력 갯수에 따라 자동으로 커링되는 함수를 사용할 수 있어요. +::: + 파이프를 통과하면서 값을 처리해요. 여러 단계에 걸쳐 값을 가공하는 코드를 선언적으로 작성할 때 유용해요. 가공하고자 하는 초기값을 `pipe` 함수에 첫번째 인자값으로 전달하고, 두번째부터는 값을 가공할 함수를 순서대로 전달하세요. 이렇게 하면 `pipe` 함첫 번째 함수는 초기값을 파라미터로 받고, 나머지 함수들은 앞선 함수가 반환하는 값을 받아 순서대로 실행되는 형태로 마지막 함수까지 실행할 수 있어요. diff --git a/docs/reference/fp/function/pipe.md b/docs/reference/fp/function/pipe.md index d845cf65b..f1038cfd6 100644 --- a/docs/reference/fp/function/pipe.md +++ b/docs/reference/fp/function/pipe.md @@ -1,5 +1,11 @@ # pipe +::: info +This function can only be imported from `es-toolkit/fp`, which supports writing code in a functional programming style. + +When import code from `es-toolkit/fp`, you can use the pipe syntax or functions that automatically curry based on the number of input arguments. +::: + Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. diff --git a/docs/zh_hans/reference/fp/function/pipe.md b/docs/zh_hans/reference/fp/function/pipe.md index 07300f4d9..cf9ac63bc 100644 --- a/docs/zh_hans/reference/fp/function/pipe.md +++ b/docs/zh_hans/reference/fp/function/pipe.md @@ -1,5 +1,11 @@ # pipe +::: info +这个函数只能从 `es-toolkit/fp` 导入,以支持函数式编程风格的代码编写。 + +从 `es-toolkit/fp` 导入函数后,可以使用管道语法或根据输入参数数量自动 curry 化的函数。 +::: + 通过管道处理值。在以声明性方式编写对值进行多步骤加工的代码时非常有用。 将要加工的初始值作为第一个参数传递给 `pipe` 函数,从第二个参数开始按顺序传递要加工的函数。这样,`pipe` 函数的第一个函数将接收初始值作为参数,其余函数将接收前一个函数返回的值,并按顺序执行,直到最后一个函数。 diff --git a/jsr.json b/jsr.json index e1f5e7158..8ff7739fc 100644 --- a/jsr.json +++ b/jsr.json @@ -3,7 +3,8 @@ "version": "1.26.1", "exports": { ".": "./src/index.ts", - "./compat": "./src/compat/index.ts" + "./compat": "./src/compat/index.ts", + "./fp": "./src/fp/index.ts" }, "publish": { "include": ["./src/**/*.ts"] diff --git a/package.json b/package.json index c4686666b..f5ad64233 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ ".": "./src/index.ts", "./array": "./src/array/index.ts", "./compat": "./src/compat/index.ts", + "./fp": "./src/fp/index.ts", "./function": "./src/function/index.ts", "./math": "./src/math/index.ts", "./object": "./src/object/index.ts", @@ -138,6 +139,16 @@ "default": "./dist/compat/index.js" } }, + "./fp": { + "import": { + "types": "./dist/fp/index.d.mts", + "default": "./dist/fp/index.mjs" + }, + "require": { + "types": "./dist/fp/index.d.ts", + "default": "./dist/fp/index.js" + } + }, "./package.json": "./package.json" } }, diff --git a/src/fp/index.ts b/src/fp/index.ts new file mode 100644 index 000000000..d8255fd2e --- /dev/null +++ b/src/fp/index.ts @@ -0,0 +1,6 @@ +export * from '../index.ts'; + +export { pipe } from './core/pipe'; +export { mapKeys } from './object/mapKeys'; +export { omit } from './object/omit'; +export { omitBy } from './object/omitBy'; \ No newline at end of file diff --git a/tests/check-dist.spec.ts b/tests/check-dist.spec.ts index 32ced69a8..4025c2f7f 100644 --- a/tests/check-dist.spec.ts +++ b/tests/check-dist.spec.ts @@ -33,6 +33,7 @@ const ENTRYPOINTS = [ './string', './util', './compat', + './fp', ]; describe(`es-toolkit's package tarball`, () => { diff --git a/vitest.config.mts b/vitest.config.mts index c931b53bd..e639c13b0 100644 --- a/vitest.config.mts +++ b/vitest.config.mts @@ -15,7 +15,7 @@ export default defineConfig({ optimizer: { ssr: { enabled: true, - include: ['es-toolkit', 'es-toolkit/compat'], + include: ['es-toolkit', 'es-toolkit/compat', 'es-toolkit/fp'], }, }, }, From 18e7eb50095edc1c9fb0931c6fdeb4302d682fda Mon Sep 17 00:00:00 2001 From: seungro Date: Sat, 16 Nov 2024 23:35:32 +0900 Subject: [PATCH 06/30] feat. add pipe.lazy --- benchmarks/package.json | 4 +- benchmarks/performance/pipe.bench.ts | 44 + src/fp/core/pipe.spec.ts | 113 ++ src/fp/core/pipe.ts | 1580 +++++++++++++++++++++++--- yarn.lock | 34 + 5 files changed, 1595 insertions(+), 180 deletions(-) create mode 100644 benchmarks/performance/pipe.bench.ts diff --git a/benchmarks/package.json b/benchmarks/package.json index 8d67522ec..dd8cb513b 100644 --- a/benchmarks/package.json +++ b/benchmarks/package.json @@ -9,10 +9,12 @@ "esbuild": "0.23.0", "lodash": "^4.17.21", "lodash-es": "^4.17.21", + "ramda": "^0.30.1", "vitest": "^2.1.2" }, "devDependencies": { "@types/lodash": "^4", - "@types/lodash-es": "^4" + "@types/lodash-es": "^4", + "@types/ramda": "^0" } } diff --git a/benchmarks/performance/pipe.bench.ts b/benchmarks/performance/pipe.bench.ts new file mode 100644 index 000000000..f04eb5f48 --- /dev/null +++ b/benchmarks/performance/pipe.bench.ts @@ -0,0 +1,44 @@ +import { bench, describe } from 'vitest'; +import { pipe as pipeToolkit_ } from 'es-toolkit/fp'; +import { pipe as pipeLodash_ } from 'lodash/fp'; +import { pipe as pipeRamda_ } from 'ramda'; + +const pipeToolkit = pipeToolkit_; +const pipeLodash = pipeLodash_; +const pipeRamda = pipeRamda_; + +function toString(value) { + return String(value); +} + +function curriedMap(mapper: (value: T) => R) { + return (arr: T[]) => { + const result: R[] = []; + + for (const item of arr) { + result.push(mapper(item)); + } + + return result; + }; +} + +function double(arr: T[]) { + const result = [...arr, ...arr]; + + return result; +} + +describe('pipe', () => { + bench('es-toolkit/fp/pipe', () => { + pipeToolkit([1, 2, 3], curriedMap(toString), double); + }); + + bench('lodash/fp/pipe', () => { + pipeLodash(curriedMap(toString), double)([1, 2, 3]); + }); + + bench('ramda/pipe', () => { + pipeRamda(curriedMap(toString), double)([1, 2, 3]); + }); +}); diff --git a/src/fp/core/pipe.spec.ts b/src/fp/core/pipe.spec.ts index 4c54456f4..9dd4cf951 100644 --- a/src/fp/core/pipe.spec.ts +++ b/src/fp/core/pipe.spec.ts @@ -31,6 +31,43 @@ describe('pipe', () => { expectTypeOf(pipe(promiseLength, isString)).toMatchTypeOf>(); }); + it('should not change original value', () => { + const curriedMap = (mapper: (value: T) => R) => { + return (arr: T[]) => { + for (let i = 0; i < arr.length; i++) { + (arr as any)[i] = mapper(arr[i]); + } + + return arr; + }; + }; + + const curriedMapValue = , R>(mapper: (value: T[string]) => R) => { + return (obj: T) => { + for (const key of Object.keys(obj)) { + (obj as any)[key] = mapper(obj[key]); + } + + return obj; + }; + }; + + const originArr = [1, 2, 3]; + + pipe(originArr, curriedMap(toString)); + + expect(originArr).toEqual([1, 2, 3]); + + const originObj = { a: 1, b: 2, c: 3 }; + + pipe( + originObj, + curriedMapValue(value => value + 5) + ); + + expect(originObj).toEqual({ a: 1, b: 2, c: 3 }); + }); + it('should inference type correctly', () => { expectTypeOf(pipe(1, toString)).toEqualTypeOf(); expectTypeOf(pipe(1, toString, isString)).toEqualTypeOf(); @@ -42,3 +79,79 @@ describe('pipe', () => { expectTypeOf(pipe(1, toStringAsync, length, isString)).toMatchTypeOf>(); }); }); + +describe('pipe.lazy', () => { + const isString = (value: unknown): value is string => typeof value === 'string'; + const toString = (value: unknown) => `string:${value}`; + const toStringAsync = (value: unknown) => + new Promise(resolve => setTimeout(() => resolve(`string:${value}`), 100)); + const length = (value: string) => value.length; + + it('should return value of the last function should be returned', () => { + expect(pipe.lazy(toString)(1)).toBe('string:1'); + expect(pipe.lazy(toString)(true)).toBe('string:true'); + expect(pipe.lazy(toString, isString)(true)).toBe(true); + + expect(pipe.lazy(toString, length)(1)).toBe(8); + expect(pipe.lazy(toString, length)(true)).toBe(11); + expect(pipe.lazy(toString, length, isString)(true)).toBe(false); + }); + + it('should return promise value if there is a function that returns a promise in the middle', async () => { + const promiseString = pipe.lazy(toStringAsync)(1); + expect(promiseString).toBeInstanceOf(Promise); + expect(await promiseString).toBe('string:1'); + + const promiseLength = pipe.lazy(toStringAsync, length)(1); + expect(promiseLength).toBeInstanceOf(Promise); + expect(await promiseLength).toBe(8); + + expectTypeOf(pipe.lazy(isString)(promiseString)).toMatchTypeOf>(); + expectTypeOf(pipe.lazy(isString)(promiseLength)).toMatchTypeOf>(); + }); + + it('should not change original value', () => { + const curriedMap = (mapper: (value: T) => R) => { + return (arr: T[]) => { + for (let i = 0; i < arr.length; i++) { + (arr as any)[i] = mapper(arr[i]); + } + + return arr; + }; + }; + + const curriedMapValue = , R>(mapper: (value: T[string]) => R) => { + return (obj: T) => { + for (const key of Object.keys(obj)) { + (obj as any)[key] = mapper(obj[key]); + } + + return obj; + }; + }; + + const originArr = [1, 2, 3]; + + pipe.lazy(curriedMap(toString))(originArr); + + expect(originArr).toEqual([1, 2, 3]); + + const originObj = { a: 1, b: 2, c: 3 }; + + pipe.lazy(curriedMapValue(value => value + 5))(originObj); + + expect(originObj).toEqual({ a: 1, b: 2, c: 3 }); + }); + + it('should inference type correctly', () => { + expectTypeOf(pipe.lazy(toString)(1)).toEqualTypeOf(); + expectTypeOf(pipe.lazy(toString, isString)(1)).toEqualTypeOf(); + expectTypeOf(pipe.lazy(toString, length)(1)).toEqualTypeOf(); + expectTypeOf(pipe.lazy(toString, length, isString)(1)).toEqualTypeOf(); + expectTypeOf(pipe.lazy(toStringAsync)(1)).toEqualTypeOf>(); + expectTypeOf(pipe.lazy(toStringAsync, length)(1)).toEqualTypeOf>(); + expectTypeOf(pipe.lazy(toStringAsync, isString)(1)).toMatchTypeOf>(); + expectTypeOf(pipe.lazy(toStringAsync, length, isString)(1)).toMatchTypeOf>(); + }); +}); diff --git a/src/fp/core/pipe.ts b/src/fp/core/pipe.ts index 06f87cca1..3bf250879 100644 --- a/src/fp/core/pipe.ts +++ b/src/fp/core/pipe.ts @@ -1,3 +1,5 @@ +import { cloneDeep } from '../../object'; + type NextFunction = Type extends 'initial' ? (arg: T) => any : T extends (args: any) => Promise @@ -29,12 +31,10 @@ type PipeReturnType = T extends /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -66,12 +66,10 @@ export function pipe>(initial: I, fn1: /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -89,18 +87,19 @@ export function pipe>(initial: I, fn1: * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe, F2 extends NextFunction>( @@ -111,12 +110,10 @@ export function pipe, F2 extends NextFu /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -135,18 +132,19 @@ export function pipe, F2 extends NextFu * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -158,12 +156,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -183,18 +179,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -207,12 +204,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -233,18 +228,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 - * + * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 - * + * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -258,12 +254,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -285,18 +279,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -311,12 +306,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -339,18 +332,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -375,12 +369,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -404,18 +396,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -442,12 +435,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -472,18 +463,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -512,12 +504,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -543,18 +533,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -585,12 +576,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -617,18 +606,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -661,12 +651,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -694,18 +682,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -740,12 +729,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -774,18 +761,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -822,12 +810,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -857,18 +843,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -907,12 +894,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -943,18 +928,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -995,12 +981,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -1032,18 +1016,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -1086,12 +1071,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -1124,18 +1107,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -1180,12 +1164,10 @@ export function pipe< /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * - * Pass the initial value you want to process as the first argument to the `pipe` function, and from the second argument onward, - * provide the functions that process the value in order. This way, the first function receives the initial value as a parameter, - * and the remaining functions receive the return value of the previous function, executing sequentially all the way to the last function. - * - * If the initial value is a `Promise` or if there are async functions in the processing chain, - * the `pipe` function will handle the value asynchronously and return a `Promise`. + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. * * @param {I} initial - The initial value to be processed. * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. @@ -1219,18 +1201,19 @@ export function pipe< * return value.length; * } * - * const result = pipe(1, toString, length); + * const result = pipe(toString, length)(1); * console.log(result); // 8 * // Use pipe with async function - * const asyncResult = await pipe(1, toStringAsync, length); + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); * console.log(asyncResult); // 8 * * // Use pipe with curried function - * const mapKeyResult = await pipe( - * { a: 1, b: 2 }, + * const pipedMapKeys = pipe.lazy( * mapKeys((value, key) => key + value) * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ export function pipe< @@ -1276,9 +1259,1248 @@ export function pipe< ): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; export function pipe(initial: any, ...functions: Array<(arg: any) => any>): any { - return getNextFunction(initial, functions); + const cloned = cloneDeep(initial); + return getNextFunction(cloned, functions); } +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1]>} A processed value - return value of 1st function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * + * const result = pipe.lazy(toString)(1); + * console.log(result); // 'string:1' + * + * // Use pipe with async function + * const pipedToStringAsync = pipe.lazy(toStringAsync); + * const asyncResult = await pipedToStringAsync(1); + * console.log(asyncResult); // 'string:1' + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy any>( + fn1: F1 +): [0]>(initial: I) => PipeReturnType<[I, F1]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2]>} A processed value - return value of 2nd function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy any, F2 extends NextFunction>( + fn1: F1, + fn2: F2 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3]>} A processed value - return value of 3rd function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy any, F2 extends NextFunction, F3 extends NextFunction>( + fn1: F1, + fn2: F2, + fn3: F3 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4]>} A processed value - return value of 4th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, +>(fn1: F1, fn2: F2, fn3: F3, fn4: F4): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5]>} A processed value - return value of 5th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>} A processed value - return value of 6th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>} A processed value - return value of 7th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>} A processed value - return value of 8th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>} A processed value - return value of 9th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>} A processed value - return value of 10th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>} A processed value - return value of 11th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11 +): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>} A processed value - return value of 12th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12 +): ( + initial: Parameters[0] +) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>} A processed value - return value of 13th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13 +): ( + initial: Parameters[0] +) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>} A processed value - return value of 14th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14 +): ( + initial: Parameters[0] +) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>} A processed value - return value of 15th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15 +): ( + initial: Parameters[0] +) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>} A processed value - return value of 16th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16 +): ( + initial: Parameters[0] +) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>} A processed value - return value of 17th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17 +): ( + initial: Parameters[0] +) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +/** + * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. + * + * When using `pipe.lazy`, do not pass the initial value as first argument of 'first function'. + * "pipe.lazy implements lazy execution by calling a function twice. + * Provide the functions that process the value in order when calling the first function, + * and pass the initial value to the function when calling the second function. + * + * @param {I} initial - The initial value to be processed. + * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. + * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. + * @param {F18 extends NextFunction} fn18 - 18th function that receives return value of 17th function as its parameter. + * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>} A processed value - return value of 18th function. + * + * @example + * function toString(value: unknown) { + * return `string:${value}`; + * } + * function toStringAsync(value: unknown) { + * return Promise.resolve(`string:${value}`); + * } + * function length(value: string) { + * return value.length; + * } + * + * const result = pipe(toString, length)(1); + * console.log(result); // 8 + + * // Use pipe with async function + * const pipedLength = pipe(toStringAsync, length); + * const asyncResult = await pipedLength(1); + * console.log(asyncResult); // 8 + * + * // Use pipe with curried function + * const pipedMapKeys = pipe.lazy( + * mapKeys((value, key) => key + value) + * ); + * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); + * console.log(mapKeyResult); // { a1: 1, b2: 2 } + */ +function pipeLazy< + F1 extends (args: any) => any, + F2 extends NextFunction, + F3 extends NextFunction, + F4 extends NextFunction, + F5 extends NextFunction, + F6 extends NextFunction, + F7 extends NextFunction, + F8 extends NextFunction, + F9 extends NextFunction, + F10 extends NextFunction, + F11 extends NextFunction, + F12 extends NextFunction, + F13 extends NextFunction, + F14 extends NextFunction, + F15 extends NextFunction, + F16 extends NextFunction, + F17 extends NextFunction, + F18 extends NextFunction, +>( + fn1: F1, + fn2: F2, + fn3: F3, + fn4: F4, + fn5: F5, + fn6: F6, + fn7: F7, + fn8: F8, + fn9: F9, + fn10: F10, + fn11: F11, + fn12: F12, + fn13: F13, + fn14: F14, + fn15: F15, + fn16: F16, + fn17: F17, + fn18: F18 +): ( + initial: Parameters[0] +) => PipeReturnType< + [Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18] +>; + +function pipeLazy(...functions: Array<(arg: any) => any>) { + return (initial: any) => { + const cloned = cloneDeep(initial); + return getNextFunction(cloned, functions); + }; +} + +pipe.lazy = pipeLazy; + function getNextFunction(prop: any, functions: Array<(arg: any) => any>) { if (functions.length === 0) { return prop; diff --git a/yarn.lock b/yarn.lock index 88882703b..51e054ab9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2554,6 +2554,15 @@ __metadata: languageName: node linkType: hard +"@types/ramda@npm:^0": + version: 0.30.2 + resolution: "@types/ramda@npm:0.30.2" + dependencies: + types-ramda: "npm:^0.30.1" + checksum: 10c0/dda95008860f594eb7b4fd9819adeb2dcd4d4e2baca6cb33f692f6f8ea76d04a7fd81f9a057c5c67555612769e5592cb15f91de6c9f8b619b8b1d806d19dc9ea + languageName: node + linkType: hard + "@types/semver@npm:^7.5.0": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" @@ -3511,10 +3520,12 @@ __metadata: dependencies: "@types/lodash": "npm:^4" "@types/lodash-es": "npm:^4" + "@types/ramda": "npm:^0" es-toolkit: "workspace:^" esbuild: "npm:0.23.0" lodash: "npm:^4.17.21" lodash-es: "npm:^4.17.21" + ramda: "npm:^0.30.1" vitest: "npm:^2.1.2" languageName: unknown linkType: soft @@ -7979,6 +7990,13 @@ __metadata: languageName: node linkType: hard +"ramda@npm:^0.30.1": + version: 0.30.1 + resolution: "ramda@npm:0.30.1" + checksum: 10c0/3ea3e35c80e1a1b78c23de0c72d3382c3446f42052b113b851f1b7fc421e33a45ce92e7aef3c705cc6de3812a209d03417af5c264f67126cda539fd66c8bea71 + languageName: node + linkType: hard + "randombytes@npm:^2.1.0": version: 2.1.0 resolution: "randombytes@npm:2.1.0" @@ -9314,6 +9332,13 @@ __metadata: languageName: node linkType: hard +"ts-toolbelt@npm:^9.6.0": + version: 9.6.0 + resolution: "ts-toolbelt@npm:9.6.0" + checksum: 10c0/838f9a2f0fe881d5065257a23b402c41315b33ff987b73db3e2b39fcb70640c4c7220e1ef118ed5676763543724fdbf4eda7b0e2c17acb667ed1401336af9f8c + languageName: node + linkType: hard + "tslib@npm:^2.0.1": version: 2.7.0 resolution: "tslib@npm:2.7.0" @@ -9473,6 +9498,15 @@ __metadata: languageName: node linkType: hard +"types-ramda@npm:^0.30.1": + version: 0.30.1 + resolution: "types-ramda@npm:0.30.1" + dependencies: + ts-toolbelt: "npm:^9.6.0" + checksum: 10c0/4a8b230ae9772e6534f65b1a154dd5604bcd1d74e27b49686337a215e83aa8fc93e49f8c49af395418d2950cb9fb9b900662077c1d4b73ff6fe4f4bcb83ab2d6 + languageName: node + linkType: hard + "typescript-eslint@npm:^8.1.0": version: 8.1.0 resolution: "typescript-eslint@npm:8.1.0" From eb493360581623a0a0a6574cbef151af2fea0d46 Mon Sep 17 00:00:00 2001 From: seungro Date: Sun, 17 Nov 2024 19:41:29 +0900 Subject: [PATCH 07/30] feat. work with map, fix pipe ts problem --- src/fp/array/map.spec.ts | 20 + src/fp/array/map.ts | 49 + src/fp/core/pipe.spec.ts | 4 +- src/fp/core/pipe.ts | 2091 ++++++++++++++++---------------------- 4 files changed, 933 insertions(+), 1231 deletions(-) create mode 100644 src/fp/array/map.spec.ts create mode 100644 src/fp/array/map.ts diff --git a/src/fp/array/map.spec.ts b/src/fp/array/map.spec.ts new file mode 100644 index 000000000..2ca0dacb8 --- /dev/null +++ b/src/fp/array/map.spec.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; +import { map } from './map'; + +describe('map', () => { + it('should return mapped value by mapper function', () => { + expect(map([1, 2, 3], value => value * 2)).toEqual([2, 4, 6]); + expect(map(value => value * 2)([1, 2, 3])).toEqual([2, 4, 6]); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3]; + const arr2 = [1, 2, 3]; + + map(arr, value => value * 2); + map(value => value * 2)(arr2); + + expect(arr).toEqual([1, 2, 3]); + expect(arr2).toEqual([1, 2, 3]); + }); +}); diff --git a/src/fp/array/map.ts b/src/fp/array/map.ts new file mode 100644 index 000000000..002b25d49 --- /dev/null +++ b/src/fp/array/map.ts @@ -0,0 +1,49 @@ +import { pipe } from '../core/pipe'; + +export function map(mapper: (value: T[number]) => R): (arr: T) => R[]; +/** + * Map each values of array by mapper function. + * + * @template T - The type of array. + * @template R - The type of mapped value. + * @param {T} arr - The array to be mapped. + * @param {(value: T[number]) => R} mapper - The function that map each items to new value. + * @returns {R[]} A new array with mapped values. + * + * @example + * const arr = [1, 2, 3]; + * const result = map(arr, value => value * 2); + * // result will be [2, 4, 6] + */ +export function map(arr: T, mapper: (value: T[number]) => R): R[]; +/** + * Map each values of array by mapper function. + * + * @template T - The type of array. + * @template R - The type of mapped value. + * @param {(value: T[number]) => R} mapper - The function that map each items to new value. + * @returns {(arr: T) => R[]} A new array with mapped values. + * + * @example + * const arr = [1, 2, 3]; + * const double = map(value => value * 2); + * const result = double(arr); + * // result will be [2, 4, 6] + */ +export function map( + arrOrMapper: T | ((value: T[number]) => R), + mapper?: (value: T[number]) => R +) { + if (mapper == null) { + return (arr: T) => map(arr, arrOrMapper as (value: T[number]) => R); + } + + const arr = arrOrMapper as T[]; + const result = []; + + for (const item of arr) { + result.push(mapper(item)); + } + + return result; +} diff --git a/src/fp/core/pipe.spec.ts b/src/fp/core/pipe.spec.ts index 9dd4cf951..59de55f94 100644 --- a/src/fp/core/pipe.spec.ts +++ b/src/fp/core/pipe.spec.ts @@ -42,10 +42,10 @@ describe('pipe', () => { }; }; - const curriedMapValue = , R>(mapper: (value: T[string]) => R) => { + const curriedMapValue = , R>(mapper: (value: T[keyof T]) => R) => { return (obj: T) => { for (const key of Object.keys(obj)) { - (obj as any)[key] = mapper(obj[key]); + (obj as any)[key] = mapper(obj[key] as any); } return obj; diff --git a/src/fp/core/pipe.ts b/src/fp/core/pipe.ts index 3bf250879..cf6c936ba 100644 --- a/src/fp/core/pipe.ts +++ b/src/fp/core/pipe.ts @@ -1,32 +1,18 @@ import { cloneDeep } from '../../object'; -type NextFunction = Type extends 'initial' - ? (arg: T) => any - : T extends (args: any) => Promise - ? (arg: R) => any - : T extends (args: any) => any - ? (arg: ReturnType) => any - : never; +type Parameter = T extends Promise ? P : T; -type PipeReturnType = T extends [infer First, ...infer Last] +type PipeReturnType = T extends [infer First, ...infer Last] ? Promised extends true - ? PipeReturnType - : Initial extends true - ? First extends Promise - ? PipeReturnType - : PipeReturnType - : First extends (args: any) => infer R - ? R extends Promise - ? PipeReturnType - : PipeReturnType - : never - : Last extends (args: any) => infer R - ? R extends Promise - ? R - : Promised extends true - ? Promise - : R - : never; + ? PipeReturnType + : First extends Promise + ? PipeReturnType + : PipeReturnType + : Last extends Promise + ? Last + : Promised extends true + ? Promise + : Last; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. @@ -36,9 +22,9 @@ type PipeReturnType = T extends * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @returns {PipeReturnType<[I, F1]>} A processed value - return value of 1st function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @returns {PipeReturnType<[T1, T2]>} A processed value - return value of 1st function. * * @example * function toString(value: unknown) { @@ -62,7 +48,7 @@ type PipeReturnType = T extends * ); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe>(initial: I, fn1: F1): PipeReturnType<[I, F1]>; +export function pipe(initial: T1, fn1: (arg: Parameter) => T2): PipeReturnType<[T1, T2]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -71,10 +57,10 @@ export function pipe>(initial: I, fn1: * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @returns {PipeReturnType<[I, F1, F2]>} A processed value - return value of 2nd function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3]>} A processed value - return value of 2nd function. * * @example * function toString(value: unknown) { @@ -102,11 +88,11 @@ export function pipe>(initial: I, fn1: * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe, F2 extends NextFunction>( - initial: I, - fn1: F1, - fn2: F2 -): PipeReturnType<[I, F1, F2]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3 +): PipeReturnType<[T1, T2, T3]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -115,11 +101,11 @@ export function pipe, F2 extends NextFu * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3]>} A processed value - return value of 3rd function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4]>} A processed value - return value of 3rd function. * * @example * function toString(value: unknown) { @@ -147,12 +133,12 @@ export function pipe, F2 extends NextFu * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, ->(initial: I, fn1: F1, fn2: F2, fn3: F3): PipeReturnType<[I, F1, F2, F3]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4 +): PipeReturnType<[T1, T2, T3, T4]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -161,12 +147,12 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4]>} A processed value - return value of 4th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5]>} A processed value - return value of 4th function. * * @example * function toString(value: unknown) { @@ -194,13 +180,13 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, ->(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4): PipeReturnType<[I, F1, F2, F3, F4]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5 +): PipeReturnType<[T1, T2, T3, T4, T5]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -209,13 +195,13 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5]>} A processed value - return value of 5th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6]>} A processed value - return value of 5th function. * * @example * function toString(value: unknown) { @@ -243,14 +229,14 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, ->(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5): PipeReturnType<[I, F1, F2, F3, F4, F5]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6 +): PipeReturnType<[T1, T2, T3, T4, T5, T6]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -259,14 +245,14 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>} A processed value - return value of 6th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7]>} A processed value - return value of 6th function. * * @example * function toString(value: unknown) { @@ -294,15 +280,15 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, ->(initial: I, fn1: F1, fn2: F2, fn3: F3, fn4: F4, fn5: F5, fn6: F6): PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -311,15 +297,15 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>} A processed value - return value of 7th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8]>} A processed value - return value of 7th function. * * @example * function toString(value: unknown) { @@ -347,25 +333,16 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -374,16 +351,16 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>} A processed value - return value of 8th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>} A processed value - return value of 8th function. * * @example * function toString(value: unknown) { @@ -411,27 +388,17 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -440,17 +407,17 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>} A processed value - return value of 9th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>} A processed value - return value of 9th function. * * @example * function toString(value: unknown) { @@ -478,29 +445,18 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -509,18 +465,18 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>} A processed value - return value of 10th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]>} A processed value - return value of 10th function. * * @example * function toString(value: unknown) { @@ -548,31 +504,19 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -581,19 +525,19 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>} A processed value - return value of 11th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]>} A processed value - return value of 11th function. * * @example * function toString(value: unknown) { @@ -621,33 +565,20 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -656,20 +587,20 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>} A processed value - return value of 12th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]>} A processed value - return value of 12th function. * * @example * function toString(value: unknown) { @@ -697,35 +628,21 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -734,21 +651,21 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>} A processed value - return value of 13th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]>} A processed value - return value of 13th function. * * @example * function toString(value: unknown) { @@ -776,37 +693,22 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -815,22 +717,22 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>} A processed value - return value of 14th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]>} A processed value - return value of 14th function. * * @example * function toString(value: unknown) { @@ -858,39 +760,23 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -899,23 +785,23 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>} A processed value - return value of 15th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]>} A processed value - return value of 15th function. * * @example * function toString(value: unknown) { @@ -943,41 +829,24 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -986,24 +855,24 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>} A processed value - return value of 16th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {(arg: Parameter) => T17} fn16 - 16th function that receives return value of 15th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]>} A processed value - return value of 16th function. * * @example * function toString(value: unknown) { @@ -1031,43 +900,25 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, - F16 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15, - fn16: F16 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16, + fn16: (arg: Parameter) => T17 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1076,25 +927,25 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. - * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>} A processed value - return value of 17th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {(arg: Parameter) => T17} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {(arg: Parameter) => T18} fn17 - 17th function that receives return value of 16th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]>} A processed value - return value of 17th function. * * @example * function toString(value: unknown) { @@ -1122,45 +973,26 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, - F16 extends NextFunction, - F17 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15, - fn16: F16, - fn17: F17 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16, + fn16: (arg: Parameter) => T17, + fn17: (arg: Parameter) => T18 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1169,26 +1001,26 @@ export function pipe< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends NextFunction} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. - * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. - * @param {F18 extends NextFunction} fn18 - 18th function that receives return value of 17th function as its parameter. - * @returns {PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>} A processed value - return value of 18th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {(arg: Parameter) => T17} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {(arg: Parameter) => T18} fn17 - 17th function that receives return value of 16th function as its parameter. + * @param {(arg: Parameter) => T19} fn18 - 18th function that receives return value of 17th function as its parameter. + * @returns {PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]>} A processed value - return value of 18th function. * * @example * function toString(value: unknown) { @@ -1216,47 +1048,27 @@ export function pipe< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -export function pipe< - I, - F1 extends NextFunction, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, - F16 extends NextFunction, - F17 extends NextFunction, - F18 extends NextFunction, ->( - initial: I, - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15, - fn16: F16, - fn17: F17, - fn18: F18 -): PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>; +export function pipe( + initial: T1, + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16, + fn16: (arg: Parameter) => T17, + fn17: (arg: Parameter) => T18, + fn18: (arg: Parameter) => T19 +): PipeReturnType<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]>; export function pipe(initial: any, ...functions: Array<(arg: any) => any>): any { const cloned = cloneDeep(initial); @@ -1271,8 +1083,8 @@ export function pipe(initial: any, ...functions: Array<(arg: any) => any>): any * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1]>} A processed value - return value of 1st function. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2]>} A processed value - return value of 1st function. * * @example * function toString(value: unknown) { @@ -1297,9 +1109,9 @@ export function pipe(initial: any, ...functions: Array<(arg: any) => any>): any * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy any>( - fn1: F1 -): [0]>(initial: I) => PipeReturnType<[I, F1]>; +function pipeLazy( + fn1: (arg: Parameter) => T2 +): >(initial: I) => PipeReturnType<[I, T2]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1308,9 +1120,9 @@ function pipeLazy any>( * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2]>} A processed value - return value of 2nd function. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3]>} A processed value - return value of 2nd function. * * @example * function toString(value: unknown) { @@ -1338,10 +1150,10 @@ function pipeLazy any>( * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy any, F2 extends NextFunction>( - fn1: F1, - fn2: F2 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3 +): >(initial: I) => PipeReturnType<[I, T2, T3]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1350,10 +1162,10 @@ function pipeLazy any, F2 extends NextFunction>( * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3]>} A processed value - return value of 3rd function. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4]>} A processed value - return value of 3rd function. * * @example * function toString(value: unknown) { @@ -1381,11 +1193,11 @@ function pipeLazy any, F2 extends NextFunction>( * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy any, F2 extends NextFunction, F3 extends NextFunction>( - fn1: F1, - fn2: F2, - fn3: F3 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1394,11 +1206,11 @@ function pipeLazy any, F2 extends NextFunction, F3 * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4]>} A processed value - return value of 4th function. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5]>} A processed value - return value of 4th function. * * @example * function toString(value: unknown) { @@ -1426,12 +1238,12 @@ function pipeLazy any, F2 extends NextFunction, F3 * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, ->(fn1: F1, fn2: F2, fn3: F3, fn4: F4): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1440,13 +1252,13 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5]>} A processed value - return value of 5th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6]>} A processed value - return value of 5th function. * * @example * function toString(value: unknown) { @@ -1474,19 +1286,13 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1495,14 +1301,14 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>} A processed value - return value of 6th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7]>} A processed value - return value of 6th function. * * @example * function toString(value: unknown) { @@ -1530,21 +1336,14 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1553,15 +1352,15 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>} A processed value - return value of 7th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8]>} A processed value - return value of 7th function. * * @example * function toString(value: unknown) { @@ -1589,23 +1388,15 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1614,16 +1405,16 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>} A processed value - return value of 8th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9]>} A processed value - return value of 8th function. * * @example * function toString(value: unknown) { @@ -1651,25 +1442,16 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1678,17 +1460,17 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>} A processed value - return value of 9th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10]>} A processed value - return value of 9th function. * * @example * function toString(value: unknown) { @@ -1716,27 +1498,17 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1745,18 +1517,18 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>} A processed value - return value of 10th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]>} A processed value - return value of 10th function. * * @example * function toString(value: unknown) { @@ -1784,29 +1556,18 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1815,19 +1576,19 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>} A processed value - return value of 11th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]>} A processed value - return value of 11th function. * * @example * function toString(value: unknown) { @@ -1855,31 +1616,19 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11 -): [0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1888,20 +1637,20 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>} A processed value - return value of 12th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]>} A processed value - return value of 12th function. * * @example * function toString(value: unknown) { @@ -1929,35 +1678,20 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12 -): ( - initial: Parameters[0] -) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13 +): >(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -1966,21 +1700,21 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>} A processed value - return value of 13th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]>} A processed value - return value of 13th function. * * @example * function toString(value: unknown) { @@ -2008,37 +1742,23 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13 -): ( - initial: Parameters[0] -) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14 +): >( + initial: I +) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -2047,22 +1767,22 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>} A processed value - return value of 14th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]>} A processed value - return value of 14th function. * * @example * function toString(value: unknown) { @@ -2090,39 +1810,24 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14 -): ( - initial: Parameters[0] -) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15 +): >( + initial: I +) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -2131,23 +1836,23 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>} A processed value - return value of 15th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]>} A processed value - return value of 15th function. * * @example * function toString(value: unknown) { @@ -2175,41 +1880,25 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15 -): ( - initial: Parameters[0] -) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16 +): >( + initial: I +) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -2218,24 +1907,24 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>} A processed value - return value of 16th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {(arg: Parameter) => T17} fn16 - 16th function that receives return value of 15th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]>} A processed value - return value of 16th function. * * @example * function toString(value: unknown) { @@ -2263,43 +1952,26 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, - F16 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15, - fn16: F16 -): ( - initial: Parameters[0] -) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16, + fn16: (arg: Parameter) => T17 +): >( + initial: I +) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -2308,25 +1980,25 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. - * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>} A processed value - return value of 17th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {(arg: Parameter) => T17} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {(arg: Parameter) => T18} fn17 - 17th function that receives return value of 16th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]>} A processed value - return value of 17th function. * * @example * function toString(value: unknown) { @@ -2354,45 +2026,27 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, - F16 extends NextFunction, - F17 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15, - fn16: F16, - fn17: F17 -): ( - initial: Parameters[0] -) => PipeReturnType<[Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17]>; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16, + fn16: (arg: Parameter) => T17, + fn17: (arg: Parameter) => T18 +): >( + initial: I +) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18]>; /** * Processes the value as it passes through pipe. It is useful for declaratively writing code that transforms a value through multiple stages. * @@ -2401,26 +2055,26 @@ function pipeLazy< * Provide the functions that process the value in order when calling the first function, * and pass the initial value to the function when calling the second function. * - * @param {I} initial - The initial value to be processed. - * @param {F1 extends (args: any) => any} fn1 - 1st function that receives initial value as its parameter. - * @param {F2 extends NextFunction} fn2 - 2nd function that receives return value of 1st function as its parameter. - * @param {F3 extends NextFunction} fn3 - 3rd function that receives return value of 2nd function as its parameter. - * @param {F4 extends NextFunction} fn4 - 4th function that receives return value of 3rd function as its parameter. - * @param {F5 extends NextFunction} fn5 - 5th function that receives return value of 4th function as its parameter. - * @param {F6 extends NextFunction} fn6 - 6th function that receives return value of 5th function as its parameter. - * @param {F7 extends NextFunction} fn7 - 7th function that receives return value of 6th function as its parameter. - * @param {F8 extends NextFunction} fn8 - 8th function that receives return value of 7th function as its parameter. - * @param {F9 extends NextFunction} fn9 - 9th function that receives return value of 8th function as its parameter. - * @param {F10 extends NextFunction} fn10 - 10th function that receives return value of 9th function as its parameter. - * @param {F11 extends NextFunction} fn11 - 11th function that receives return value of 10th function as its parameter. - * @param {F12 extends NextFunction} fn12 - 12th function that receives return value of 11th function as its parameter. - * @param {F13 extends NextFunction} fn13 - 13th function that receives return value of 12th function as its parameter. - * @param {F14 extends NextFunction} fn14 - 14th function that receives return value of 13th function as its parameter. - * @param {F15 extends NextFunction} fn15 - 15th function that receives return value of 14th function as its parameter. - * @param {F16 extends NextFunction} fn16 - 16th function that receives return value of 15th function as its parameter. - * @param {F17 extends NextFunction} fn17 - 17th function that receives return value of 16th function as its parameter. - * @param {F18 extends NextFunction} fn18 - 18th function that receives return value of 17th function as its parameter. - * @returns {[0]>(initial: I) => PipeReturnType<[I, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18]>} A processed value - return value of 18th function. + * @param {T1} initial - The initial value to be processed. + * @param {(arg: Parameter) => T2} fn1 - 1st function that receives initial value as its parameter. + * @param {(arg: Parameter) => T3} fn2 - 2nd function that receives return value of 1st function as its parameter. + * @param {(arg: Parameter) => T4} fn3 - 3rd function that receives return value of 2nd function as its parameter. + * @param {(arg: Parameter) => T5} fn4 - 4th function that receives return value of 3rd function as its parameter. + * @param {(arg: Parameter) => T6} fn5 - 5th function that receives return value of 4th function as its parameter. + * @param {(arg: Parameter) => T7} fn6 - 6th function that receives return value of 5th function as its parameter. + * @param {(arg: Parameter) => T8} fn7 - 7th function that receives return value of 6th function as its parameter. + * @param {(arg: Parameter) => T9} fn8 - 8th function that receives return value of 7th function as its parameter. + * @param {(arg: Parameter) => T10} fn9 - 9th function that receives return value of 8th function as its parameter. + * @param {(arg: Parameter) => T11} fn10 - 10th function that receives return value of 9th function as its parameter. + * @param {(arg: Parameter) => T12} fn11 - 11th function that receives return value of 10th function as its parameter. + * @param {(arg: Parameter) => T13} fn12 - 12th function that receives return value of 11th function as its parameter. + * @param {(arg: Parameter) => T14} fn13 - 13th function that receives return value of 12th function as its parameter. + * @param {(arg: Parameter) => T15} fn14 - 14th function that receives return value of 13th function as its parameter. + * @param {(arg: Parameter) => T16} fn15 - 15th function that receives return value of 14th function as its parameter. + * @param {(arg: Parameter) => T17} fn16 - 16th function that receives return value of 15th function as its parameter. + * @param {(arg: Parameter) => T18} fn17 - 17th function that receives return value of 16th function as its parameter. + * @param {(arg: Parameter) => T19} fn18 - 18th function that receives return value of 17th function as its parameter. + * @returns {(initial: I) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]>} A processed value - return value of 18th function. * * @example * function toString(value: unknown) { @@ -2448,49 +2102,28 @@ function pipeLazy< * const mapKeyResult = await pipedMapKeys({ a: 1, b: 2 }); * console.log(mapKeyResult); // { a1: 1, b2: 2 } */ -function pipeLazy< - F1 extends (args: any) => any, - F2 extends NextFunction, - F3 extends NextFunction, - F4 extends NextFunction, - F5 extends NextFunction, - F6 extends NextFunction, - F7 extends NextFunction, - F8 extends NextFunction, - F9 extends NextFunction, - F10 extends NextFunction, - F11 extends NextFunction, - F12 extends NextFunction, - F13 extends NextFunction, - F14 extends NextFunction, - F15 extends NextFunction, - F16 extends NextFunction, - F17 extends NextFunction, - F18 extends NextFunction, ->( - fn1: F1, - fn2: F2, - fn3: F3, - fn4: F4, - fn5: F5, - fn6: F6, - fn7: F7, - fn8: F8, - fn9: F9, - fn10: F10, - fn11: F11, - fn12: F12, - fn13: F13, - fn14: F14, - fn15: F15, - fn16: F16, - fn17: F17, - fn18: F18 -): ( - initial: Parameters[0] -) => PipeReturnType< - [Parameters[0], F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18] ->; +function pipeLazy( + fn1: (arg: Parameter) => T2, + fn2: (arg: Parameter) => T3, + fn3: (arg: Parameter) => T4, + fn4: (arg: Parameter) => T5, + fn5: (arg: Parameter) => T6, + fn6: (arg: Parameter) => T7, + fn7: (arg: Parameter) => T8, + fn8: (arg: Parameter) => T9, + fn9: (arg: Parameter) => T10, + fn10: (arg: Parameter) => T11, + fn11: (arg: Parameter) => T12, + fn12: (arg: Parameter) => T13, + fn13: (arg: Parameter) => T14, + fn14: (arg: Parameter) => T15, + fn15: (arg: Parameter) => T16, + fn16: (arg: Parameter) => T17, + fn17: (arg: Parameter) => T18, + fn18: (arg: Parameter) => T19 +): >( + initial: I +) => PipeReturnType<[I, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19]>; function pipeLazy(...functions: Array<(arg: any) => any>) { return (initial: any) => { From 1825bea4510c4f5a63391c71d7331c5f8ae71cd6 Mon Sep 17 00:00:00 2001 From: seungro Date: Mon, 18 Nov 2024 00:43:14 +0900 Subject: [PATCH 08/30] feat. change fp script implementation - use refer, copy test file --- .scripts/fp/create-fp-version.sh | 1 + .scripts/fp/toPipable.ts | 27 +++++++++++++++++----- src/fp/object/mapKeys.spec.ts | 16 +++++++++++++ src/fp/object/mapKeys.ts | 14 +++--------- src/fp/object/omit.spec.ts | 29 ++++++++++++++++++++++++ src/fp/object/omit.ts | 21 ++++++++--------- src/fp/object/omitBy.spec.ts | 39 ++++++++++++++++++++++++++++++++ src/fp/object/omitBy.ts | 16 ++++--------- 8 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 src/fp/object/mapKeys.spec.ts create mode 100644 src/fp/object/omit.spec.ts create mode 100644 src/fp/object/omitBy.spec.ts diff --git a/.scripts/fp/create-fp-version.sh b/.scripts/fp/create-fp-version.sh index 3b31aa062..0437e28ae 100644 --- a/.scripts/fp/create-fp-version.sh +++ b/.scripts/fp/create-fp-version.sh @@ -1,6 +1,7 @@ FUNC=$1 find ./src -name "$1.ts" -maxdepth 2 -exec sh -c 'mkdir -p "./src/fp/$(dirname "{}" | sed "s|^./src/||")" && cp "{}" "./src/fp/$(dirname "{}" | sed "s|^./src/||")/"' \; +find ./src -name "$1.spec.ts" -maxdepth 2 -exec sh -c 'mkdir -p "./src/fp/$(dirname "{}" | sed "s|^./src/||")" && cp "{}" "./src/fp/$(dirname "{}" | sed "s|^./src/||")/"' \; FP_FILENAME=$(find ./src/fp -name "$1.ts") yarn jscodeshift -t ./.scripts/fp/toPipable.ts $FP_FILENAME yarn prettier --write $FP_FILENAME \ No newline at end of file diff --git a/.scripts/fp/toPipable.ts b/.scripts/fp/toPipable.ts index e83ab9d05..5c55767f3 100644 --- a/.scripts/fp/toPipable.ts +++ b/.scripts/fp/toPipable.ts @@ -1,16 +1,19 @@ -import { API, FileInfo, TSTypeAnnotation } from 'jscodeshift'; import { TSTypeKind } from 'ast-types/gen/kinds'; +import { API, FileInfo, TSTypeAnnotation } from 'jscodeshift'; +import { getFunctionDeclaration } from './_internal/getter/functionDeclaration'; +import { getTypedParam } from './_internal/getter/typedParam'; +import { Param } from './_internal/types'; import { isValidFunctionDeclaration } from './_internal/validator/functionDeclaration'; import { isValidParams } from './_internal/validator/params'; -import { Param } from './_internal/types'; -import { getTypedParam } from './_internal/getter/typedParam'; -import { getFunctionDeclaration } from './_internal/getter/functionDeclaration'; export const parser = 'tsx'; export default function transformer(file: FileInfo, api: API) { const j = api.jscodeshift; + const categoryRegResult = /fp\/([a-z]+)/.exec(file.path); + const category = categoryRegResult ? categoryRegResult[1] : ''; + return j(file.source) .find(j.ExportNamedDeclaration) .forEach(path => { @@ -21,7 +24,6 @@ export default function transformer(file: FileInfo, api: API) { } const functionName = functionDeclaration.id.name; - const functionBody = functionDeclaration.body; const params = functionDeclaration.params; @@ -67,13 +69,20 @@ export default function transformer(file: FileInfo, api: API) { ]), ]); + const referrerCallStatement = j.returnStatement( + j.callExpression(j.identifier(`${functionName}Toolkit`), [ + j.identifier(originParams.first.name), + j.identifier(originParams.second.name), + ]) + ); + params[0].name = newFirstArgumentName; params[0].typeAnnotation = j.tsTypeAnnotation( j.tsUnionType([originParams.first.type, originParams.second.type].map(j.tsParenthesizedType)) ); params[1].name = `${originParams.second.name}?`; - functionDeclaration.body = j.blockStatement([...curringConditionalStatement.body, ...functionBody.body]); + functionDeclaration.body = j.blockStatement([...curringConditionalStatement.body, referrerCallStatement]); const nonCurriedDeclaration = getFunctionDeclaration( { @@ -106,6 +115,12 @@ export default function transformer(file: FileInfo, api: API) { functionDeclaration.returnType = undefined; + const referrerImportDeclaration = j.importDeclaration( + [j.importSpecifier(j.identifier(functionName), j.identifier(`${functionName}Toolkit`))], + j.literal(`../../${category}/${functionName}`) + ); + + j(path).insertBefore(referrerImportDeclaration); j(path).insertBefore(nonCurriedDeclaration); j(path).insertBefore(curriedDeclaration); }) diff --git a/src/fp/object/mapKeys.spec.ts b/src/fp/object/mapKeys.spec.ts new file mode 100644 index 000000000..71dcf38e3 --- /dev/null +++ b/src/fp/object/mapKeys.spec.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from 'vitest'; +import { mapKeys } from './mapKeys'; + +describe('mapKeys', () => { + it('should iterate over and map the object using its own string keys', () => { + expect(mapKeys({ a: 1, b: 2, c: 3 }, (_, key) => `${key}a`)).toEqual({ aa: 1, ba: 2, ca: 3 }); + }); + + it('should iterate over and map the object using its own number keys', () => { + expect(mapKeys({ 1: 'a', 2: 'b', 3: 'c' }, (_, key) => key * 2)).toEqual({ 2: 'a', 4: 'b', 6: 'c' }); + }); + + it('should pass the value corresponding to the current key into the iteratee', () => { + expect(mapKeys({ a: 1, b: 2, c: 3 }, value => value)).toEqual({ 1: 1, 2: 2, 3: 3 }); + }); +}); diff --git a/src/fp/object/mapKeys.ts b/src/fp/object/mapKeys.ts index cf3d58845..e7ffcdcfc 100644 --- a/src/fp/object/mapKeys.ts +++ b/src/fp/object/mapKeys.ts @@ -1,3 +1,5 @@ +import { mapKeys as mapKeysToolkit } from '../../object/mapKeys'; + export function mapKeys( object: T, getNewKey: (value: T[K1], key: K1, object: T) => K2 @@ -32,15 +34,5 @@ export function mapKeys; - const keys = Object.keys(object); - - for (let i = 0; i < keys.length; i++) { - const key = keys[i] as K1; - const value = object[key]; - - result[getNewKey(value, key, object)] = value as any; - } - - return result; + return mapKeysToolkit(object, getNewKey); } diff --git a/src/fp/object/omit.spec.ts b/src/fp/object/omit.spec.ts new file mode 100644 index 000000000..da750d5bf --- /dev/null +++ b/src/fp/object/omit.spec.ts @@ -0,0 +1,29 @@ +import { describe, expect, it } from 'vitest'; +import { omit } from './omit'; + +describe('omit', () => { + it('should omit properties from an object', () => { + const object = { foo: 1, bar: 2, baz: 3 }; + const result = omit(object, ['foo', 'bar']); + expect(result).toEqual({ baz: 3 }); + }); + + it('should return an empty object if all keys are omitted', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omit(obj, ['a', 'b', 'c']); + expect(result).toEqual({}); + }); + + it('should return the same object if no keys are omitted', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omit(obj, []); + expect(result).toEqual({ a: 1, b: 2, c: 3 }); + }); + + it('should not affect the original object', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omit(obj, ['b']); + expect(result).toEqual({ a: 1, c: 3 }); + expect(obj).toEqual({ a: 1, b: 2, c: 3 }); + }); +}); diff --git a/src/fp/object/omit.ts b/src/fp/object/omit.ts index 03c6cb0a3..7b7803390 100644 --- a/src/fp/object/omit.ts +++ b/src/fp/object/omit.ts @@ -1,5 +1,7 @@ -export function omit, K extends keyof T>(obj: T, keys: K[]): Omit; -export function omit, K extends keyof T>(keys: K[]): (obj: T) => Omit; +import { omit as omitToolkit } from '../../object/omit'; + +export function omit, K extends keyof T>(obj: T, keys: readonly K[]): Omit; +export function omit, K extends keyof T>(keys: readonly K[]): (obj: T) => Omit; /** * Creates a new object with specified keys omitted. * @@ -17,17 +19,14 @@ export function omit, K extends keyof T>(keys: K[] * const result = omit(obj, ['b', 'c']); * // result will be { a: 1 } */ -export function omit, K extends keyof T>(objOrKeys: T | K[], keys?: K[]) { +export function omit, K extends keyof T>( + objOrKeys: T | readonly K[], + keys?: readonly K[] +) { if (keys == null) { - return (obj: T) => omit(obj, objOrKeys as K[]); + return (obj: T) => omit(obj, objOrKeys as readonly K[]); } const obj = objOrKeys as T; - const result = { ...obj }; - - for (const key of keys) { - delete result[key]; - } - - return result as Omit; + return omitToolkit(obj, keys); } diff --git a/src/fp/object/omitBy.spec.ts b/src/fp/object/omitBy.spec.ts new file mode 100644 index 000000000..52c2d67c6 --- /dev/null +++ b/src/fp/object/omitBy.spec.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from 'vitest'; +import { omitBy } from './omitBy'; + +describe('omitBy', () => { + it('should omit properties based on the predicate function', () => { + const obj = { a: 1, b: 'omit', c: 3 }; + const shouldOmit = (value: number | string) => typeof value === 'string'; + const result = omitBy(obj, shouldOmit); + expect(result).toEqual({ a: 1, c: 3 }); + }); + + it('should return an empty object if all properties are omitted', () => { + const obj = { a: 'omit', b: 'omit' }; + const shouldOmit = (value: string) => typeof value === 'string'; + const result = omitBy(obj, shouldOmit); + expect(result).toEqual({}); + }); + + it('should return the same object if no properties are omitted', () => { + const obj = { a: 1, b: 2, c: 3 }; + const shouldOmit = (value: number) => typeof value === 'string'; + const result = omitBy(obj, shouldOmit); + expect(result).toEqual(obj); + }); + + it('should work with an empty object', () => { + const obj = {}; + const shouldOmit = (value: never) => value; + const result = omitBy(obj, shouldOmit); + expect(result).toEqual({}); + }); + + it('should work with nested objects', () => { + const obj = { a: 1, b: { nested: 'omit' }, c: 3 }; + const shouldOmit = (_: number | { nested: string }, key: string) => key === 'b'; + const result = omitBy(obj, shouldOmit); + expect(result).toEqual({ a: 1, c: 3 }); + }); +}); diff --git a/src/fp/object/omitBy.ts b/src/fp/object/omitBy.ts index 4c4eda92f..102511b3b 100644 --- a/src/fp/object/omitBy.ts +++ b/src/fp/object/omitBy.ts @@ -1,3 +1,5 @@ +import { omitBy as omitByToolkit } from '../../object/omitBy'; + export function omitBy>( obj: T, shouldOmit: (value: T[keyof T], key: keyof T) => boolean @@ -20,7 +22,7 @@ export function omitBy>( * * @example * const obj = { a: 1, b: 'omit', c: 3 }; - * const shouldOmit = (key, value) => typeof value === 'string'; + * const shouldOmit = (value) => typeof value === 'string'; * const result = omitBy(obj, shouldOmit); * // result will be { a: 1, c: 3 } */ @@ -33,15 +35,5 @@ export function omitBy>( } const obj = objOrShouldOmit as T; - const result: Partial = {}; - - for (const [key, value] of Object.entries(obj)) { - if (shouldOmit(value, key)) { - continue; - } - - (result as any)[key] = value; - } - - return result; + return omitByToolkit(obj, shouldOmit); } From 8a407d985f80bd2691b407835fae16c6dcc581de Mon Sep 17 00:00:00 2001 From: seungro Date: Mon, 18 Nov 2024 01:30:29 +0900 Subject: [PATCH 09/30] feat. add comment on declarations --- .../_internal/getter/functionDeclaration.ts | 6 ++++- .scripts/fp/toPipable.ts | 7 +++++ src/fp/object/mapKeys.ts | 26 +++++++++++++++--- src/fp/object/omit.ts | 21 ++++++++++++++- src/fp/object/omitBy.ts | 27 ++++++++++++++++--- 5 files changed, 79 insertions(+), 8 deletions(-) diff --git a/.scripts/fp/_internal/getter/functionDeclaration.ts b/.scripts/fp/_internal/getter/functionDeclaration.ts index 460eb27f7..1ee0bd263 100644 --- a/.scripts/fp/_internal/getter/functionDeclaration.ts +++ b/.scripts/fp/_internal/getter/functionDeclaration.ts @@ -1,3 +1,4 @@ +import { CommentKind } from 'ast-types/gen/kinds'; import { FunctionDeclaration, Identifier, @@ -25,8 +26,11 @@ export function getFunctionDeclaration( j: JSCodeshift ) { const newFunctionDeclaration = j.template.statement([ - `export function ${functionName}(${params.name.join(', ')});\n`, + ` + export function ${functionName}(${params.name.join(', ')});\n\n + `, ]) as { + comments?: CommentKind[]; declaration: Omit & { params: Identifier[]; }; diff --git a/.scripts/fp/toPipable.ts b/.scripts/fp/toPipable.ts index 5c55767f3..2cf708bd3 100644 --- a/.scripts/fp/toPipable.ts +++ b/.scripts/fp/toPipable.ts @@ -17,6 +17,7 @@ export default function transformer(file: FileInfo, api: API) { return j(file.source) .find(j.ExportNamedDeclaration) .forEach(path => { + const comments = [...(path.value.comments ?? [])]; const functionDeclaration = path.value.declaration; if (!isValidFunctionDeclaration(functionDeclaration)) { @@ -97,6 +98,8 @@ export default function transformer(file: FileInfo, api: API) { j ); + nonCurriedDeclaration.comments = [j.commentBlock(comments[0].value, true)]; + const returnOfCurried = j.tsFunctionType([getTypedParam(originParams.first, j)]); returnOfCurried.typeAnnotation = functionDeclaration.returnType as TSTypeAnnotation; @@ -113,6 +116,10 @@ export default function transformer(file: FileInfo, api: API) { j ); + curriedDeclaration.comments = [j.commentBlock(comments[0].value, true)]; + + path.value.comments = null; + functionDeclaration.returnType = undefined; const referrerImportDeclaration = j.importDeclaration( diff --git a/src/fp/object/mapKeys.ts b/src/fp/object/mapKeys.ts index e7ffcdcfc..c8e077e37 100644 --- a/src/fp/object/mapKeys.ts +++ b/src/fp/object/mapKeys.ts @@ -1,12 +1,28 @@ import { mapKeys as mapKeysToolkit } from '../../object/mapKeys'; +/** + * Creates a new object with the same values as the given object, but with keys generated + * by running each own enumerable property of the object through the iteratee function. + * + * @template T - The type of the object. + * @template K1 - The type of the keys in the object. + * @template K2 - The type of the new keys generated by the iteratee function. + * + * @param {T} object - The object to iterate over. + * @param {(value: T[K1], key: K1, object: T) => K2} getNewKey - The function invoked per own enumerable property. + * @returns {Record} - Returns the new mapped object. + * + * @example + * // Example usage: + * const obj = { a: 1, b: 2 }; + * const result = mapKeys(obj, (value, key) => key + value); + * console.log(result); // { a1: 1, b2: 2 } + */ export function mapKeys( object: T, getNewKey: (value: T[K1], key: K1, object: T) => K2 ): Record; -export function mapKeys( - getNewKey: (value: T[K1], key: K1, object: T) => K2 -): (object: T) => Record; + /** * Creates a new object with the same values as the given object, but with keys generated * by running each own enumerable property of the object through the iteratee function. @@ -25,6 +41,10 @@ export function mapKeys key + value); * console.log(result); // { a1: 1, b2: 2 } */ +export function mapKeys( + getNewKey: (value: T[K1], key: K1, object: T) => K2 +): (object: T) => Record; + export function mapKeys( objectOrGetNewKey: T | ((value: T[K1], key: K1, object: T) => K2), getNewKey?: (value: T[K1], key: K1, object: T) => K2 diff --git a/src/fp/object/omit.ts b/src/fp/object/omit.ts index 7b7803390..4421f9612 100644 --- a/src/fp/object/omit.ts +++ b/src/fp/object/omit.ts @@ -1,7 +1,24 @@ import { omit as omitToolkit } from '../../object/omit'; +/** + * Creates a new object with specified keys omitted. + * + * This function takes an object and an array of keys, and returns a new object that + * excludes the properties corresponding to the specified keys. + * + * @template T - The type of object. + * @template K - The type of keys in object. + * @param {T} obj - The object to omit keys from. + * @param {K[]} keys - An array of keys to be omitted from the object. + * @returns {Omit} A new object with the specified keys omitted. + * + * @example + * const obj = { a: 1, b: 2, c: 3 }; + * const result = omit(obj, ['b', 'c']); + * // result will be { a: 1 } + */ export function omit, K extends keyof T>(obj: T, keys: readonly K[]): Omit; -export function omit, K extends keyof T>(keys: readonly K[]): (obj: T) => Omit; + /** * Creates a new object with specified keys omitted. * @@ -19,6 +36,8 @@ export function omit, K extends keyof T>(keys: rea * const result = omit(obj, ['b', 'c']); * // result will be { a: 1 } */ +export function omit, K extends keyof T>(keys: readonly K[]): (obj: T) => Omit; + export function omit, K extends keyof T>( objOrKeys: T | readonly K[], keys?: readonly K[] diff --git a/src/fp/object/omitBy.ts b/src/fp/object/omitBy.ts index 102511b3b..b553c63ac 100644 --- a/src/fp/object/omitBy.ts +++ b/src/fp/object/omitBy.ts @@ -1,12 +1,29 @@ import { omitBy as omitByToolkit } from '../../object/omitBy'; +/** + * Creates a new object composed of the properties that do not satisfy the predicate function. + * + * This function takes an object and a predicate function, and returns a new object that + * includes only the properties for which the predicate function returns false. + * + * @template T - The type of object. + * @param {T} obj - The object to omit properties from. + * @param {(value: T[string], key: keyof T) => boolean} shouldOmit - A predicate function that determines + * whether a property should be omitted. It takes the property's key and value as arguments and returns `true` + * if the property should be omitted, and `false` otherwise. + * @returns {Partial} A new object with the properties that do not satisfy the predicate function. + * + * @example + * const obj = { a: 1, b: 'omit', c: 3 }; + * const shouldOmit = (value) => typeof value === 'string'; + * const result = omitBy(obj, shouldOmit); + * // result will be { a: 1, c: 3 } + */ export function omitBy>( obj: T, shouldOmit: (value: T[keyof T], key: keyof T) => boolean ): Partial; -export function omitBy>( - shouldOmit: (value: T[keyof T], key: keyof T) => boolean -): (obj: T) => Partial; + /** * Creates a new object composed of the properties that do not satisfy the predicate function. * @@ -26,6 +43,10 @@ export function omitBy>( * const result = omitBy(obj, shouldOmit); * // result will be { a: 1, c: 3 } */ +export function omitBy>( + shouldOmit: (value: T[keyof T], key: keyof T) => boolean +): (obj: T) => Partial; + export function omitBy>( objOrShouldOmit: T | ((value: T[keyof T], key: keyof T) => boolean), shouldOmit?: (value: T[keyof T], key: keyof T) => boolean From fca6795974ea92fa0627c4403a09ff939baa2a1d Mon Sep 17 00:00:00 2001 From: seungro Date: Mon, 18 Nov 2024 01:58:38 +0900 Subject: [PATCH 10/30] feat. update fp scripts - automatically update comments of curried one --- .scripts/fp/toPipable.ts | 31 ++++++++++++++++++++++++++++++- src/fp/object/mapKeys.ts | 3 +-- src/fp/object/omit.ts | 3 +-- src/fp/object/omitBy.ts | 3 +-- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/.scripts/fp/toPipable.ts b/.scripts/fp/toPipable.ts index 2cf708bd3..feef6b4cf 100644 --- a/.scripts/fp/toPipable.ts +++ b/.scripts/fp/toPipable.ts @@ -116,7 +116,36 @@ export default function transformer(file: FileInfo, api: API) { j ); - curriedDeclaration.comments = [j.commentBlock(comments[0].value, true)]; + const firstParamLine = comments[0].value.split('\n').find(line => line.startsWith(' * @param')) ?? ''; + + // if(firstParamLine === undefined) { + // } else { + // } + + const firstParamRegResult = /{([^}]+)} ([^\s]+)/.exec(firstParamLine); + + if (firstParamRegResult == null) { + curriedDeclaration.comments = [j.commentBlock(comments[0].value, true)]; + } else { + const [_, typeName, paramName] = firstParamRegResult; + + curriedDeclaration.comments = [ + j.commentBlock( + comments[0].value.replace(`${firstParamLine}\n`, '').replace( + /@returns {([^}]+)} (.+)/, + (_, returnType, note) => + `@returns {(${paramName}: ${typeName}) => ${returnType}} A function that receive ${firstParamLine + .split('-')[1] + .trim() + .replace(/\.$/, '') + .replace(/^./, firstLetter => firstLetter.toLowerCase())} as argument and returns ${String(note) + .replace(/\.$/, '') + .replace(/^./, firstLetter => firstLetter.toLowerCase())}.` + ), + true + ), + ]; + } path.value.comments = null; diff --git a/src/fp/object/mapKeys.ts b/src/fp/object/mapKeys.ts index c8e077e37..cd01f68a3 100644 --- a/src/fp/object/mapKeys.ts +++ b/src/fp/object/mapKeys.ts @@ -31,9 +31,8 @@ export function mapKeys K2} getNewKey - The function invoked per own enumerable property. - * @returns {Record} - Returns the new mapped object. + * @returns {(object: T) => Record} A function that receive the object to iterate over as argument and returns the new mapped object. * * @example * // Example usage: diff --git a/src/fp/object/omit.ts b/src/fp/object/omit.ts index 4421f9612..1ac0005ef 100644 --- a/src/fp/object/omit.ts +++ b/src/fp/object/omit.ts @@ -27,9 +27,8 @@ export function omit, K extends keyof T>(obj: T, k * * @template T - The type of object. * @template K - The type of keys in object. - * @param {T} obj - The object to omit keys from. * @param {K[]} keys - An array of keys to be omitted from the object. - * @returns {Omit} A new object with the specified keys omitted. + * @returns {(obj: T) => Omit} A function that receive the object to omit keys from as argument and returns a new object with the specified keys omitted. * * @example * const obj = { a: 1, b: 2, c: 3 }; diff --git a/src/fp/object/omitBy.ts b/src/fp/object/omitBy.ts index b553c63ac..85b694272 100644 --- a/src/fp/object/omitBy.ts +++ b/src/fp/object/omitBy.ts @@ -31,11 +31,10 @@ export function omitBy>( * includes only the properties for which the predicate function returns false. * * @template T - The type of object. - * @param {T} obj - The object to omit properties from. * @param {(value: T[string], key: keyof T) => boolean} shouldOmit - A predicate function that determines * whether a property should be omitted. It takes the property's key and value as arguments and returns `true` * if the property should be omitted, and `false` otherwise. - * @returns {Partial} A new object with the properties that do not satisfy the predicate function. + * @returns {(obj: T) => Partial} A function that receive the object to omit properties from as argument and returns a new object with the properties that do not satisfy the predicate function. * * @example * const obj = { a: 1, b: 'omit', c: 3 }; From 7f56077627952f2c3801b9481fc03e33e73f3605 Mon Sep 17 00:00:00 2001 From: seungro Date: Tue, 19 Nov 2024 16:07:57 +0900 Subject: [PATCH 11/30] feat. replace example of curried one --- .scripts/fp/toPipable.ts | 28 +++++++++++++++++++++------- src/fp/object/mapKeys.ts | 4 ++-- src/fp/object/omit.ts | 2 +- src/fp/object/omitBy.ts | 2 +- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/.scripts/fp/toPipable.ts b/.scripts/fp/toPipable.ts index feef6b4cf..19b4982db 100644 --- a/.scripts/fp/toPipable.ts +++ b/.scripts/fp/toPipable.ts @@ -18,6 +18,7 @@ export default function transformer(file: FileInfo, api: API) { .find(j.ExportNamedDeclaration) .forEach(path => { const comments = [...(path.value.comments ?? [])]; + const comment = comments[0].value; const functionDeclaration = path.value.declaration; if (!isValidFunctionDeclaration(functionDeclaration)) { @@ -116,22 +117,35 @@ export default function transformer(file: FileInfo, api: API) { j ); - const firstParamLine = comments[0].value.split('\n').find(line => line.startsWith(' * @param')) ?? ''; - - // if(firstParamLine === undefined) { - // } else { - // } + const firstParamLine = comment.split('\n').find(line => line.startsWith(' * @param')) ?? ''; const firstParamRegResult = /{([^}]+)} ([^\s]+)/.exec(firstParamLine); if (firstParamRegResult == null) { - curriedDeclaration.comments = [j.commentBlock(comments[0].value, true)]; + curriedDeclaration.comments = [j.commentBlock(comment, true)]; } else { const [_, typeName, paramName] = firstParamRegResult; + const exampleComments = comment.split('@example')[1]; + + const usageExampleLine = exampleComments + .split('\n') + .find(comment => new RegExp(`${functionName}\(.+\);`).test(comment)); + + const curriedComment = + usageExampleLine == null + ? comment + : comment.replace( + usageExampleLine, + usageExampleLine.replace( + new RegExp(`${functionName}\\(([^,]+), (.+)\\);`), + (_, firstParam, secondParam) => `${functionName}(${String(secondParam).trim()})(${firstParam});` + ) + ); + curriedDeclaration.comments = [ j.commentBlock( - comments[0].value.replace(`${firstParamLine}\n`, '').replace( + curriedComment.replace(`${firstParamLine}\n`, '').replace( /@returns {([^}]+)} (.+)/, (_, returnType, note) => `@returns {(${paramName}: ${typeName}) => ${returnType}} A function that receive ${firstParamLine diff --git a/src/fp/object/mapKeys.ts b/src/fp/object/mapKeys.ts index cd01f68a3..51a5589a4 100644 --- a/src/fp/object/mapKeys.ts +++ b/src/fp/object/mapKeys.ts @@ -32,12 +32,12 @@ export function mapKeys K2} getNewKey - The function invoked per own enumerable property. - * @returns {(object: T) => Record} A function that receive the object to iterate over as argument and returns the new mapped object. + * @returns {(object: T) => Record} A function that receive the object to iterate over as argument and returns - Returns the new mapped object. * * @example * // Example usage: * const obj = { a: 1, b: 2 }; - * const result = mapKeys(obj, (value, key) => key + value); + * const result = mapKeys((value, key) => key + value)(obj); * console.log(result); // { a1: 1, b2: 2 } */ export function mapKeys( diff --git a/src/fp/object/omit.ts b/src/fp/object/omit.ts index 1ac0005ef..73532acb4 100644 --- a/src/fp/object/omit.ts +++ b/src/fp/object/omit.ts @@ -32,7 +32,7 @@ export function omit, K extends keyof T>(obj: T, k * * @example * const obj = { a: 1, b: 2, c: 3 }; - * const result = omit(obj, ['b', 'c']); + * const result = omit(['b', 'c'])(obj); * // result will be { a: 1 } */ export function omit, K extends keyof T>(keys: readonly K[]): (obj: T) => Omit; diff --git a/src/fp/object/omitBy.ts b/src/fp/object/omitBy.ts index 85b694272..9eab47d34 100644 --- a/src/fp/object/omitBy.ts +++ b/src/fp/object/omitBy.ts @@ -39,7 +39,7 @@ export function omitBy>( * @example * const obj = { a: 1, b: 'omit', c: 3 }; * const shouldOmit = (value) => typeof value === 'string'; - * const result = omitBy(obj, shouldOmit); + * const result = omitBy(shouldOmit)(obj); * // result will be { a: 1, c: 3 } */ export function omitBy>( From 97f009db70406f36ff15043bcf26eba9178c6400 Mon Sep 17 00:00:00 2001 From: seungro Date: Tue, 19 Nov 2024 22:00:46 +0900 Subject: [PATCH 12/30] fix. fix fp/omitBy type --- .scripts/fp/create-fp-version.sh | 2 + .scripts/fp/toPipable.ts | 1 + .scripts/fp/toPipableSpec.ts | 76 ++++++++++++++++++++++++++++++++ src/fp/object/omitBy.spec.ts | 47 +++++++++++++++++--- src/fp/object/omitBy.ts | 39 ++++++++-------- 5 files changed, 140 insertions(+), 25 deletions(-) create mode 100644 .scripts/fp/toPipableSpec.ts diff --git a/.scripts/fp/create-fp-version.sh b/.scripts/fp/create-fp-version.sh index 0437e28ae..f63a17627 100644 --- a/.scripts/fp/create-fp-version.sh +++ b/.scripts/fp/create-fp-version.sh @@ -3,5 +3,7 @@ FUNC=$1 find ./src -name "$1.ts" -maxdepth 2 -exec sh -c 'mkdir -p "./src/fp/$(dirname "{}" | sed "s|^./src/||")" && cp "{}" "./src/fp/$(dirname "{}" | sed "s|^./src/||")/"' \; find ./src -name "$1.spec.ts" -maxdepth 2 -exec sh -c 'mkdir -p "./src/fp/$(dirname "{}" | sed "s|^./src/||")" && cp "{}" "./src/fp/$(dirname "{}" | sed "s|^./src/||")/"' \; FP_FILENAME=$(find ./src/fp -name "$1.ts") +FP_SPEC_FILENAME=$(find ./src/fp -name "$1.spec.ts") yarn jscodeshift -t ./.scripts/fp/toPipable.ts $FP_FILENAME +yarn jscodeshift -t ./.scripts/fp/toPipableSpec.ts $FP_SPEC_FILENAME yarn prettier --write $FP_FILENAME \ No newline at end of file diff --git a/.scripts/fp/toPipable.ts b/.scripts/fp/toPipable.ts index 19b4982db..00b765d04 100644 --- a/.scripts/fp/toPipable.ts +++ b/.scripts/fp/toPipable.ts @@ -14,6 +14,7 @@ export default function transformer(file: FileInfo, api: API) { const categoryRegResult = /fp\/([a-z]+)/.exec(file.path); const category = categoryRegResult ? categoryRegResult[1] : ''; + j.FunctionDeclaration; return j(file.source) .find(j.ExportNamedDeclaration) .forEach(path => { diff --git a/.scripts/fp/toPipableSpec.ts b/.scripts/fp/toPipableSpec.ts new file mode 100644 index 000000000..de8dac26f --- /dev/null +++ b/.scripts/fp/toPipableSpec.ts @@ -0,0 +1,76 @@ +import { namedTypes as n } from 'ast-types'; +import { TSTypeKind } from 'ast-types/gen/kinds'; +import { API, CallExpression, FileInfo, Identifier, StringLiteral, TSTypeAnnotation } from 'jscodeshift'; +import { getFunctionDeclaration } from './_internal/getter/functionDeclaration'; +import { getTypedParam } from './_internal/getter/typedParam'; +import { Param } from './_internal/types'; +import { isValidFunctionDeclaration } from './_internal/validator/functionDeclaration'; +import { isValidParams } from './_internal/validator/params'; +import { cloneDeep } from '../../src/compat'; + +export const parser = 'tsx'; + +export default function transformer(file: FileInfo, api: API) { + const j = api.jscodeshift; + + const categoryRegResult = /fp\/([a-zA-Z]+)\/([a-zA-Z]+)/.exec(file.path); + const category = categoryRegResult ? categoryRegResult[1] : ''; + const fileName = categoryRegResult ? categoryRegResult[2] : ''; + + j.FunctionDeclaration; + const firstTouched = j(file.source) + .find(j.CallExpression, node => n.Identifier.check(node.callee) && node.callee.name === 'describe') + .forEach(path => { + if (n.StringLiteral.check(path.value.arguments[0])) { + path.value.arguments[0].value = `${path.value.arguments[0].value}/fp`; + } + }) + .find(j.ExpressionStatement, node => { + return ( + n.CallExpression.check(node.expression) && + n.Identifier.check(node.expression.callee) && + node.expression.callee.name === 'it' + ); + }) + .forEach(path => { + const expression = path.value.expression as CallExpression; + const firstArgument = expression.arguments[0] as StringLiteral; + j(path).insertBefore( + j.expressionStatement( + j.callExpression(j.identifier('it'), [ + j.stringLiteral(`(non-curried) ${firstArgument.value}`), + expression.arguments[1], + ]) + ) + ); + + firstArgument.value = `(curried) ${firstArgument.value}`; + }) + .toSource(); + + return j(firstTouched) + .find( + j.CallExpression, + node => + n.Identifier.check(node.callee) && + n.StringLiteral.check(node.arguments[0]) && + node.callee.name === 'it' && + node.arguments[0].value.includes('(curried)') + ) + .forEach(path => { + j(path) + .find(j.CallExpression, { + callee: { name: fileName }, + }) + .forEach(omitCall => { + const [firstParameter, secondParameter] = omitCall.value.arguments; + + console.log(firstParameter); + + omitCall.value.arguments = [secondParameter]; + const curried = j.callExpression(omitCall.value, [firstParameter]); + omitCall.replace(curried); + }); + }) + .toSource(); +} diff --git a/src/fp/object/omitBy.spec.ts b/src/fp/object/omitBy.spec.ts index 52c2d67c6..12d6fef99 100644 --- a/src/fp/object/omitBy.spec.ts +++ b/src/fp/object/omitBy.spec.ts @@ -1,39 +1,74 @@ import { describe, expect, it } from 'vitest'; import { omitBy } from './omitBy'; -describe('omitBy', () => { - it('should omit properties based on the predicate function', () => { +describe('omitBy/fp', () => { + it('(non-curried) should omit properties based on the predicate function', () => { const obj = { a: 1, b: 'omit', c: 3 }; const shouldOmit = (value: number | string) => typeof value === 'string'; const result = omitBy(obj, shouldOmit); expect(result).toEqual({ a: 1, c: 3 }); }); - it('should return an empty object if all properties are omitted', () => { + it('(curried) should omit properties based on the predicate function', () => { + const obj = { a: 1, b: 'omit', c: 3 }; + const shouldOmit = (value: number | string) => typeof value === 'string'; + const result = omitBy(shouldOmit)(obj); + expect(result).toEqual({ a: 1, c: 3 }); + }); + + it('(non-curried) should return an empty object if all properties are omitted', () => { const obj = { a: 'omit', b: 'omit' }; const shouldOmit = (value: string) => typeof value === 'string'; const result = omitBy(obj, shouldOmit); expect(result).toEqual({}); }); - it('should return the same object if no properties are omitted', () => { + it('(curried) should return an empty object if all properties are omitted', () => { + const obj = { a: 'omit', b: 'omit' }; + const shouldOmit = (value: string) => typeof value === 'string'; + const result = omitBy(shouldOmit)(obj); + expect(result).toEqual({}); + }); + + it('(non-curried) should return the same object if no properties are omitted', () => { const obj = { a: 1, b: 2, c: 3 }; const shouldOmit = (value: number) => typeof value === 'string'; const result = omitBy(obj, shouldOmit); expect(result).toEqual(obj); }); - it('should work with an empty object', () => { + it('(curried) should return the same object if no properties are omitted', () => { + const obj = { a: 1, b: 2, c: 3 }; + const shouldOmit = (value: number) => typeof value === 'string'; + const result = omitBy(shouldOmit)(obj); + expect(result).toEqual(obj); + }); + + it('(non-curried) should work with an empty object', () => { const obj = {}; const shouldOmit = (value: never) => value; const result = omitBy(obj, shouldOmit); expect(result).toEqual({}); }); - it('should work with nested objects', () => { + it('(curried) should work with an empty object', () => { + const obj = {}; + const shouldOmit = (value: never) => value; + const result = omitBy(shouldOmit)(obj); + expect(result).toEqual({}); + }); + + it('(non-curried) should work with nested objects', () => { const obj = { a: 1, b: { nested: 'omit' }, c: 3 }; const shouldOmit = (_: number | { nested: string }, key: string) => key === 'b'; const result = omitBy(obj, shouldOmit); expect(result).toEqual({ a: 1, c: 3 }); }); + + it('(curried) should work with nested objects', () => { + const obj = { a: 1, b: { nested: 'omit' }, c: 3 }; + const shouldOmit = (_: number | { nested: string }, key: string) => key === 'b'; + const result = omitBy(shouldOmit)(obj); + expect(result).toEqual({ a: 1, c: 3 }); + }); }); diff --git a/src/fp/object/omitBy.ts b/src/fp/object/omitBy.ts index 9eab47d34..90e44b22a 100644 --- a/src/fp/object/omitBy.ts +++ b/src/fp/object/omitBy.ts @@ -6,12 +6,13 @@ import { omitBy as omitByToolkit } from '../../object/omitBy'; * This function takes an object and a predicate function, and returns a new object that * includes only the properties for which the predicate function returns false. * - * @template T - The type of object. - * @param {T} obj - The object to omit properties from. - * @param {(value: T[string], key: keyof T) => boolean} shouldOmit - A predicate function that determines + * @template T - The type of object value. + * @template O - The type of object. + * @param {O} obj - The object to omit properties from. + * @param {(value: T, key: keyof O) => boolean} shouldOmit - A predicate function that determines * whether a property should be omitted. It takes the property's key and value as arguments and returns `true` * if the property should be omitted, and `false` otherwise. - * @returns {Partial} A new object with the properties that do not satisfy the predicate function. + * @returns {Partial} A new object with the properties that do not satisfy the predicate function. * * @example * const obj = { a: 1, b: 'omit', c: 3 }; @@ -19,10 +20,10 @@ import { omitBy as omitByToolkit } from '../../object/omitBy'; * const result = omitBy(obj, shouldOmit); * // result will be { a: 1, c: 3 } */ -export function omitBy>( - obj: T, - shouldOmit: (value: T[keyof T], key: keyof T) => boolean -): Partial; +export function omitBy>( + obj: O, + shouldOmit: (value: T, key: keyof O) => boolean +): Partial; /** * Creates a new object composed of the properties that do not satisfy the predicate function. @@ -30,11 +31,11 @@ export function omitBy>( * This function takes an object and a predicate function, and returns a new object that * includes only the properties for which the predicate function returns false. * - * @template T - The type of object. - * @param {(value: T[string], key: keyof T) => boolean} shouldOmit - A predicate function that determines + * @template T - The type of object value. + * @param {(value: T, key: string) => boolean} shouldOmit - A predicate function that determines * whether a property should be omitted. It takes the property's key and value as arguments and returns `true` * if the property should be omitted, and `false` otherwise. - * @returns {(obj: T) => Partial} A function that receive the object to omit properties from as argument and returns a new object with the properties that do not satisfy the predicate function. + * @returns {(obj: Record) => Partial} A function that receive the object to omit properties from as argument and returns a new object with the properties that do not satisfy the predicate function. * * @example * const obj = { a: 1, b: 'omit', c: 3 }; @@ -42,18 +43,18 @@ export function omitBy>( * const result = omitBy(shouldOmit)(obj); * // result will be { a: 1, c: 3 } */ -export function omitBy>( - shouldOmit: (value: T[keyof T], key: keyof T) => boolean -): (obj: T) => Partial; +export function omitBy( + shouldOmit: (value: T, key: string) => boolean +): (obj: Record) => Partial>; -export function omitBy>( - objOrShouldOmit: T | ((value: T[keyof T], key: keyof T) => boolean), - shouldOmit?: (value: T[keyof T], key: keyof T) => boolean +export function omitBy>( + objOrShouldOmit: O | ((value: T, key: keyof O) => boolean), + shouldOmit?: (value: T, key: keyof O) => boolean ) { if (shouldOmit == null) { - return (obj: T) => omitBy(obj, objOrShouldOmit as (value: T[keyof T], key: keyof T) => boolean); + return (obj: O) => omitBy(obj, objOrShouldOmit as (value: T, key: keyof O) => boolean); } - const obj = objOrShouldOmit as T; + const obj = objOrShouldOmit as O; return omitByToolkit(obj, shouldOmit); } From 956196cf94a8fc01728727d95da5bf20028c1c00 Mon Sep 17 00:00:00 2001 From: seungro Date: Tue, 19 Nov 2024 22:16:22 +0900 Subject: [PATCH 13/30] fix. fix mapKeys type --- .scripts/fp/toPipableSpec.ts | 7 ------- src/fp/object/mapKeys.spec.ts | 18 +++++++++++++++--- src/fp/object/mapKeys.ts | 12 ++++++------ src/fp/object/omit.spec.ts | 33 +++++++++++++++++++++++++++++---- src/fp/object/omitBy.spec.ts | 2 +- 5 files changed, 51 insertions(+), 21 deletions(-) diff --git a/.scripts/fp/toPipableSpec.ts b/.scripts/fp/toPipableSpec.ts index de8dac26f..c2cbe4023 100644 --- a/.scripts/fp/toPipableSpec.ts +++ b/.scripts/fp/toPipableSpec.ts @@ -14,17 +14,10 @@ export default function transformer(file: FileInfo, api: API) { const j = api.jscodeshift; const categoryRegResult = /fp\/([a-zA-Z]+)\/([a-zA-Z]+)/.exec(file.path); - const category = categoryRegResult ? categoryRegResult[1] : ''; const fileName = categoryRegResult ? categoryRegResult[2] : ''; j.FunctionDeclaration; const firstTouched = j(file.source) - .find(j.CallExpression, node => n.Identifier.check(node.callee) && node.callee.name === 'describe') - .forEach(path => { - if (n.StringLiteral.check(path.value.arguments[0])) { - path.value.arguments[0].value = `${path.value.arguments[0].value}/fp`; - } - }) .find(j.ExpressionStatement, node => { return ( n.CallExpression.check(node.expression) && diff --git a/src/fp/object/mapKeys.spec.ts b/src/fp/object/mapKeys.spec.ts index 71dcf38e3..e30496b24 100644 --- a/src/fp/object/mapKeys.spec.ts +++ b/src/fp/object/mapKeys.spec.ts @@ -2,15 +2,27 @@ import { describe, expect, it } from 'vitest'; import { mapKeys } from './mapKeys'; describe('mapKeys', () => { - it('should iterate over and map the object using its own string keys', () => { + it('(non-curried) should iterate over and map the object using its own string keys', () => { expect(mapKeys({ a: 1, b: 2, c: 3 }, (_, key) => `${key}a`)).toEqual({ aa: 1, ba: 2, ca: 3 }); }); - it('should iterate over and map the object using its own number keys', () => { + it('(curried) should iterate over and map the object using its own string keys', () => { + expect(mapKeys((_, key) => `${key}a`)({ a: 1, b: 2, c: 3 })).toEqual({ aa: 1, ba: 2, ca: 3 }); + }); + + it('(non-curried) should iterate over and map the object using its own number keys', () => { expect(mapKeys({ 1: 'a', 2: 'b', 3: 'c' }, (_, key) => key * 2)).toEqual({ 2: 'a', 4: 'b', 6: 'c' }); }); - it('should pass the value corresponding to the current key into the iteratee', () => { + it('(curried) should iterate over and map the object using its own number keys', () => { + expect(mapKeys((_, key: number) => key * 2)({ 1: 'a', 2: 'b', 3: 'c' })).toEqual({ 2: 'a', 4: 'b', 6: 'c' }); + }); + + it('(non-curried) should pass the value corresponding to the current key into the iteratee', () => { expect(mapKeys({ a: 1, b: 2, c: 3 }, value => value)).toEqual({ 1: 1, 2: 2, 3: 3 }); }); + + it('(curried) should pass the value corresponding to the current key into the iteratee', () => { + expect(mapKeys((value: number) => value)({ a: 1, b: 2, c: 3 })).toEqual({ 1: 1, 2: 2, 3: 3 }); + }); }); diff --git a/src/fp/object/mapKeys.ts b/src/fp/object/mapKeys.ts index 51a5589a4..6ce9c424c 100644 --- a/src/fp/object/mapKeys.ts +++ b/src/fp/object/mapKeys.ts @@ -27,12 +27,12 @@ export function mapKeys K2} getNewKey - The function invoked per own enumerable property. - * @returns {(object: T) => Record} A function that receive the object to iterate over as argument and returns - Returns the new mapped object. + * @param {(value: V, key: K1, object: Record) => K2} getNewKey - The function invoked per own enumerable property. + * @returns {(object: Record) => Record} A function that receive the object to iterate over as argument and returns - Returns the new mapped object. * * @example * // Example usage: @@ -40,9 +40,9 @@ export function mapKeys key + value)(obj); * console.log(result); // { a1: 1, b2: 2 } */ -export function mapKeys( - getNewKey: (value: T[K1], key: K1, object: T) => K2 -): (object: T) => Record; +export function mapKeys( + getNewKey: (value: V, key: K1, object: Record) => K2 +): (object: Record) => Record; export function mapKeys( objectOrGetNewKey: T | ((value: T[K1], key: K1, object: T) => K2), diff --git a/src/fp/object/omit.spec.ts b/src/fp/object/omit.spec.ts index da750d5bf..dea20db95 100644 --- a/src/fp/object/omit.spec.ts +++ b/src/fp/object/omit.spec.ts @@ -2,28 +2,53 @@ import { describe, expect, it } from 'vitest'; import { omit } from './omit'; describe('omit', () => { - it('should omit properties from an object', () => { + it('(non-curried) should omit properties from an object', () => { const object = { foo: 1, bar: 2, baz: 3 }; const result = omit(object, ['foo', 'bar']); expect(result).toEqual({ baz: 3 }); }); - it('should return an empty object if all keys are omitted', () => { + it('(curried) should omit properties from an object', () => { + const object = { foo: 1, bar: 2, baz: 3 }; + const result = omit(['foo', 'bar'])(object); + expect(result).toEqual({ baz: 3 }); + }); + + it('(non-curried) should return an empty object if all keys are omitted', () => { const obj = { a: 1, b: 2, c: 3 }; const result = omit(obj, ['a', 'b', 'c']); expect(result).toEqual({}); }); - it('should return the same object if no keys are omitted', () => { + it('(curried) should return an empty object if all keys are omitted', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omit(['a', 'b', 'c'])(obj); + expect(result).toEqual({}); + }); + + it('(non-curried) should return the same object if no keys are omitted', () => { const obj = { a: 1, b: 2, c: 3 }; const result = omit(obj, []); expect(result).toEqual({ a: 1, b: 2, c: 3 }); }); - it('should not affect the original object', () => { + it('(curried) should return the same object if no keys are omitted', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omit([])(obj); + expect(result).toEqual({ a: 1, b: 2, c: 3 }); + }); + + it('(non-curried) should not affect the original object', () => { const obj = { a: 1, b: 2, c: 3 }; const result = omit(obj, ['b']); expect(result).toEqual({ a: 1, c: 3 }); expect(obj).toEqual({ a: 1, b: 2, c: 3 }); }); + + it('(curried) should not affect the original object', () => { + const obj = { a: 1, b: 2, c: 3 }; + const result = omit(['b'])(obj); + expect(result).toEqual({ a: 1, c: 3 }); + expect(obj).toEqual({ a: 1, b: 2, c: 3 }); + }); }); diff --git a/src/fp/object/omitBy.spec.ts b/src/fp/object/omitBy.spec.ts index 12d6fef99..8350f5d94 100644 --- a/src/fp/object/omitBy.spec.ts +++ b/src/fp/object/omitBy.spec.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; import { omitBy } from './omitBy'; -describe('omitBy/fp', () => { +describe('omitBy', () => { it('(non-curried) should omit properties based on the predicate function', () => { const obj = { a: 1, b: 'omit', c: 3 }; const shouldOmit = (value: number | string) => typeof value === 'string'; From 1ce89887515a3ad3ac34f4394edd3bef368b9dc7 Mon Sep 17 00:00:00 2001 From: seungro Date: Tue, 19 Nov 2024 22:40:17 +0900 Subject: [PATCH 14/30] add at, chunk, compact, countBy, difference to fp --- .scripts/fp/toPipableSpec.ts | 2 - src/fp/array/at.spec.ts | 40 +++++++++++++++++ src/fp/array/at.ts | 43 ++++++++++++++++++ src/fp/array/chunk.spec.ts | 78 +++++++++++++++++++++++++++++++++ src/fp/array/chunk.ts | 59 +++++++++++++++++++++++++ src/fp/array/compact.spec.ts | 24 ++++++++++ src/fp/array/compact.ts | 25 +++++++++++ src/fp/array/countBy.spec.ts | 50 +++++++++++++++++++++ src/fp/array/countBy.ts | 70 +++++++++++++++++++++++++++++ src/fp/array/difference.spec.ts | 16 +++++++ src/fp/array/difference.ts | 57 ++++++++++++++++++++++++ 11 files changed, 462 insertions(+), 2 deletions(-) create mode 100644 src/fp/array/at.spec.ts create mode 100644 src/fp/array/at.ts create mode 100644 src/fp/array/chunk.spec.ts create mode 100644 src/fp/array/chunk.ts create mode 100644 src/fp/array/compact.spec.ts create mode 100644 src/fp/array/compact.ts create mode 100644 src/fp/array/countBy.spec.ts create mode 100644 src/fp/array/countBy.ts create mode 100644 src/fp/array/difference.spec.ts create mode 100644 src/fp/array/difference.ts diff --git a/.scripts/fp/toPipableSpec.ts b/.scripts/fp/toPipableSpec.ts index c2cbe4023..9fe85c058 100644 --- a/.scripts/fp/toPipableSpec.ts +++ b/.scripts/fp/toPipableSpec.ts @@ -58,8 +58,6 @@ export default function transformer(file: FileInfo, api: API) { .forEach(omitCall => { const [firstParameter, secondParameter] = omitCall.value.arguments; - console.log(firstParameter); - omitCall.value.arguments = [secondParameter]; const curried = j.callExpression(omitCall.value, [firstParameter]); omitCall.replace(curried); diff --git a/src/fp/array/at.spec.ts b/src/fp/array/at.spec.ts new file mode 100644 index 000000000..65fce3d58 --- /dev/null +++ b/src/fp/array/at.spec.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from 'vitest'; +import { at } from './at'; + +describe('at', () => { + it('(non-curried) should return the elements corresponding to the specified keys', () => { + expect(at(['a', 'b', 'c'], [0, 2])).toEqual(['a', 'c']); + expect(at(['a', 'b', 'c'], [2, 0])).toEqual(['c', 'a']); + }); + + it('(curried) should return the elements corresponding to the specified keys', () => { + expect(at([0, 2])(['a', 'b', 'c'])).toEqual(['a', 'c']); + expect(at([2, 0])(['a', 'b', 'c'])).toEqual(['c', 'a']); + }); + + it('(non-curried) should support negative indices', () => { + expect(at(['a', 'b', 'c'], [-1, -2])).toEqual(['c', 'b']); + expect(at(['a', 'b', 'c'], [-2, -1])).toEqual(['b', 'c']); + }); + + it('(curried) should support negative indices', () => { + expect(at([-1, -2])(['a', 'b', 'c'])).toEqual(['c', 'b']); + expect(at([-2, -1])(['a', 'b', 'c'])).toEqual(['b', 'c']); + }); + + it('(non-curried) should return `undefined` for nonexistent keys', () => { + expect(at(['a', 'b', 'c'], [2, 4, 0])).toEqual(['c', undefined, 'a']); + }); + + it('(curried) should return `undefined` for nonexistent keys', () => { + expect(at([2, 4, 0])(['a', 'b', 'c'])).toEqual(['c', undefined, 'a']); + }); + + it('(non-curried) should return an empty array when no keys are given', () => { + expect(at(['a', 'b', 'c'], [])).toEqual([]); + }); + + it('(curried) should return an empty array when no keys are given', () => { + expect(at([])(['a', 'b', 'c'])).toEqual([]); + }); +}); diff --git a/src/fp/array/at.ts b/src/fp/array/at.ts new file mode 100644 index 000000000..c440baa8e --- /dev/null +++ b/src/fp/array/at.ts @@ -0,0 +1,43 @@ +import { at as atToolkit } from '../../array/at'; + +/** + * Retrieves elements from an array at the specified indices. + * + * This function supports negative indices, which count from the end of the array. + * + * @template T + * @param {readonly T[]} arr - The array to retrieve elements from. + * @param {number[]} indices - An array of indices specifying the positions of elements to retrieve. + * @returns {Array} A new array containing the elements at the specified indices. + * + * @example + * const numbers = [10, 20, 30, 40, 50]; + * const result = at(numbers, [1, 3, 4]); + * console.log(result); // [20, 40, 50] + */ +export function at(arr: readonly T[], indices: number[]): Array; + +/** + * Retrieves elements from an array at the specified indices. + * + * This function supports negative indices, which count from the end of the array. + * + * @template T + * @param {number[]} indices - An array of indices specifying the positions of elements to retrieve. + * @returns {(arr: readonly T[]) => Array} A function that receive the array to retrieve elements from as argument and returns a new array containing the elements at the specified indices. + * + * @example + * const numbers = [10, 20, 30, 40, 50]; + * const result = at([1, 3, 4])(numbers); + * console.log(result); // [20, 40, 50] + */ +export function at(indices: number[]): (arr: readonly T[]) => Array; + +export function at(arrOrIndices: readonly T[] | number[], indices?: number[]) { + if (indices == null) { + return (arr: readonly T[]) => at(arr, arrOrIndices as number[]); + } + + const arr = arrOrIndices as readonly T[]; + return atToolkit(arr, indices); +} diff --git a/src/fp/array/chunk.spec.ts b/src/fp/array/chunk.spec.ts new file mode 100644 index 000000000..48890a45e --- /dev/null +++ b/src/fp/array/chunk.spec.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from 'vitest'; +import { chunk } from './chunk'; + +describe('chunk', () => { + it( + "(non-curried) should return an empty array when the input array is empty", + () => { + expect(chunk([], 3)).toEqual([]); + } + ); + + it("(curried) should return an empty array when the input array is empty", () => { + expect(chunk(3)([])).toEqual([]); + }); + + it( + "(non-curried) should throw if the size is not an integer of is less than 1", + () => { + expect(() => chunk([1, 2, 3], 0)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], -1)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], 0.5)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], Math.PI)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + } + ); + + it("(curried) should throw if the size is not an integer of is less than 1", () => { + expect(() => chunk(0)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk(-1)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk(0.5)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk(Math.PI)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + }); + + it( + "(non-curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size", + () => { + expect(chunk([1, 2, 3, 4, 5, 6], 3)).toEqual([ + [1, 2, 3], + [4, 5, 6], + ]); + } + ); + + it("(curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size", () => { + expect(chunk(3)([1, 2, 3, 4, 5, 6])).toEqual([ + [1, 2, 3], + [4, 5, 6], + ]); + }); + + it( + "(non-curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size", + () => { + expect(chunk([1, 2, 3, 4], 6)).toEqual([[1, 2, 3, 4]]); + expect(chunk([1, 2, 3, 4, 5, 6, 7], 2)).toEqual([[1, 2], [3, 4], [5, 6], [7]]); + } + ); + + it("(curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size", () => { + expect(chunk(6)([1, 2, 3, 4])).toEqual([[1, 2, 3, 4]]); + expect(chunk(2)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2], [3, 4], [5, 6], [7]]); + }); +}); diff --git a/src/fp/array/chunk.ts b/src/fp/array/chunk.ts new file mode 100644 index 000000000..934ef56cc --- /dev/null +++ b/src/fp/array/chunk.ts @@ -0,0 +1,59 @@ +import { chunk as chunkToolkit } from '../../array/chunk'; + +/** + * Splits an array into smaller arrays of a specified length. + * + * This function takes an input array and divides it into multiple smaller arrays, + * each of a specified length. If the input array cannot be evenly divided, + * the final sub-array will contain the remaining elements. + * + * @template T The type of elements in the array. + * @param {T[]} arr - The array to be chunked into smaller arrays. + * @param {number} size - The size of each smaller array. Must be a positive integer. + * @returns {T[][]} A two-dimensional array where each sub-array has a maximum length of `size`. + * @throws {Error} Throws an error if `size` is not a positive integer. + * + * @example + * // Splits an array of numbers into sub-arrays of length 2 + * chunk([1, 2, 3, 4, 5], 2); + * // Returns: [[1, 2], [3, 4], [5]] + * + * @example + * // Splits an array of strings into sub-arrays of length 3 + * chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3); + * // Returns: [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']] + */ +export function chunk(arr: readonly T[], size: number): T[][]; + +/** + * Splits an array into smaller arrays of a specified length. + * + * This function takes an input array and divides it into multiple smaller arrays, + * each of a specified length. If the input array cannot be evenly divided, + * the final sub-array will contain the remaining elements. + * + * @template T The type of elements in the array. + * @param {number} size - The size of each smaller array. Must be a positive integer. + * @returns {(arr: T[]) => T[][]} A function that receive the array to be chunked into smaller arrays as argument and returns a two-dimensional array where each sub-array has a maximum length of `size`. + * @throws {Error} Throws an error if `size` is not a positive integer. + * + * @example + * // Splits an array of numbers into sub-arrays of length 2 + * chunk(2, 3, 4, 5], 2)([1); + * // Returns: [[1, 2], [3, 4], [5]] + * + * @example + * // Splits an array of strings into sub-arrays of length 3 + * chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3); + * // Returns: [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']] + */ +export function chunk(size: number): (arr: readonly T[]) => T[][]; + +export function chunk(arrOrSize: readonly T[] | number, size?: number) { + if (size == null) { + return (arr: readonly T[]) => chunk(arr, arrOrSize as number); + } + + const arr = arrOrSize as readonly T[]; + return chunkToolkit(arr, size); +} diff --git a/src/fp/array/compact.spec.ts b/src/fp/array/compact.spec.ts new file mode 100644 index 000000000..01eac9619 --- /dev/null +++ b/src/fp/array/compact.spec.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest'; +import { compact } from './compact'; + +describe('compact', () => { + it("(non-curried) removes falsey values from array", () => { + expect(compact([0, 1, false, 2, '', 3, null, undefined, 4, NaN, 5])).toEqual([1, 2, 3, 4, 5]); + expect(compact([false, 0, '', null, undefined, NaN])).toEqual([]); + expect(compact([0, { name: 'John' }, false, 'hello', null, { age: 30 }, undefined, NaN])).toEqual([ + { name: 'John' }, + 'hello', + { age: 30 }, + ]); + }); + + it("(curried) removes falsey values from array", () => { + expect(compact()([0, 1, false, 2, '', 3, null, undefined, 4, NaN, 5])).toEqual([1, 2, 3, 4, 5]); + expect(compact()([false, 0, '', null, undefined, NaN])).toEqual([]); + expect(compact()([0, { name: 'John' }, false, 'hello', null, { age: 30 }, undefined, NaN])).toEqual([ + { name: 'John' }, + 'hello', + { age: 30 }, + ]); + }); +}); diff --git a/src/fp/array/compact.ts b/src/fp/array/compact.ts new file mode 100644 index 000000000..358dc7981 --- /dev/null +++ b/src/fp/array/compact.ts @@ -0,0 +1,25 @@ +type NotFalsey = Exclude; + +/** + * Removes falsey values (false, null, 0, 0n, '', undefined, NaN) from an array. + * + * @template T - The type of elements in the array. + * @param {T[]} arr - The input array to remove falsey values. + * @returns {Array>} - A new array with all falsey values removed. + * + * @example + * compact([0, 0n, 1, false, 2, '', 3, null, undefined, 4, NaN, 5]); + * Returns: [1, 2, 3, 4, 5] + */ +export function compact(arr: readonly T[]): Array> { + const result: Array> = []; + + for (let i = 0; i < arr.length; i++) { + const item = arr[i]; + if (item) { + result.push(item as NotFalsey); + } + } + + return result; +} diff --git a/src/fp/array/countBy.spec.ts b/src/fp/array/countBy.spec.ts new file mode 100644 index 000000000..310740915 --- /dev/null +++ b/src/fp/array/countBy.spec.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from 'vitest'; +import { countBy } from './countBy.ts'; + +describe('countBy', () => { + it('(non-curried) should count the occurrences of each item in an array', () => { + const arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]; + const result = countBy(arr, String); + + expect(result).toEqual({ + '1': 2, + '2': 2, + '3': 2, + '4': 2, + '5': 2, + }); + }); + + it('(curried) should count the occurrences of each item in an array', () => { + const arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]; + const result = countBy(String)(arr); + + expect(result).toEqual({ + '1': 2, + '2': 2, + '3': 2, + '4': 2, + '5': 2, + }); + }); + + it('(non-curried) should count the occurrences of each item in an array that applied transformer', () => { + const arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]; + const result = countBy(arr, item => (item % 2 === 0 ? 'even' : 'odd')); + + expect(result).toEqual({ + odd: 6, + even: 4, + }); + }); + + it('(curried) should count the occurrences of each item in an array that applied transformer', () => { + const arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]; + const result = countBy((item: number) => (item % 2 === 0 ? 'even' : 'odd'))(arr); + + expect(result).toEqual({ + odd: 6, + even: 4, + }); + }); +}); diff --git a/src/fp/array/countBy.ts b/src/fp/array/countBy.ts new file mode 100644 index 000000000..bce367b7c --- /dev/null +++ b/src/fp/array/countBy.ts @@ -0,0 +1,70 @@ +import { countBy as countByToolkit } from '../../array/countBy'; + +/** + * Count the occurrences of each item in an array + * based on a transformation function. + * + * This function takes an array and a transformation function + * that converts each item in the array to a key. It then + * counts the occurrences of each transformed item and returns + * an object with the transformed items as keys and the counts + * as values. + * + * @template T - The type of the items in the input array. + * @template K - The type of keys. + * @param {T[]} arr - The input array to count occurrences. + * @param {(item: T) => K} mapper - The transformation function that maps each item to a key. + * @returns {Record} An object containing the transformed items as keys and the + * counts as values. + * + * @example + * const array = ['a', 'b', 'c', 'a', 'b', 'a']; + * const result = countBy(array, x => x); + * // result will be { a: 3, b: 2, c: 1 } + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = countBy(array, item => item % 2 === 0 ? 'even' : 'odd'); + * // result will be { odd: 3, even: 2 } + */ +export function countBy(arr: readonly T[], mapper: (item: T) => K): Record; + +/** + * Count the occurrences of each item in an array + * based on a transformation function. + * + * This function takes an array and a transformation function + * that converts each item in the array to a key. It then + * counts the occurrences of each transformed item and returns + * an object with the transformed items as keys and the counts + * as values. + * + * @template T - The type of the items in the input array. + * @template K - The type of keys. + * @param {(item: T) => K} mapper - The transformation function that maps each item to a key. + * @returns {(arr: T[]) => Record} A function that receive the input array to count occurrences as argument and returns an object containing the transformed items as keys and the. + * counts as values. + * + * @example + * const array = ['a', 'b', 'c', 'a', 'b', 'a']; + * const result = countBy(x => x)(array); + * // result will be { a: 3, b: 2, c: 1 } + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = countBy(array, item => item % 2 === 0 ? 'even' : 'odd'); + * // result will be { odd: 3, even: 2 } + */ +export function countBy(mapper: (item: T) => K): (arr: readonly T[]) => Record; + +export function countBy( + arrOrMapper: readonly T[] | ((item: T) => K), + mapper?: (item: T) => K +) { + if (mapper == null) { + return (arr: readonly T[]) => countBy(arr, arrOrMapper as (item: T) => K); + } + + const arr = arrOrMapper as readonly T[]; + return countByToolkit(arr, mapper); +} diff --git a/src/fp/array/difference.spec.ts b/src/fp/array/difference.spec.ts new file mode 100644 index 000000000..44b25d6f6 --- /dev/null +++ b/src/fp/array/difference.spec.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from 'vitest'; +import { difference } from './difference'; + +describe('difference', () => { + it("(non-curried) should the difference of two arrays", () => { + expect(difference([1, 2, 3], [1])).toEqual([2, 3]); + expect(difference([], [1, 2, 3])).toEqual([]); + expect(difference([1, 2, 3, 4], [2, 4])).toEqual([1, 3]); + }); + + it("(curried) should the difference of two arrays", () => { + expect(difference([1])([1, 2, 3])).toEqual([2, 3]); + expect(difference([1, 2, 3])([])).toEqual([]); + expect(difference([2, 4])([1, 2, 3, 4])).toEqual([1, 3]); + }); +}); diff --git a/src/fp/array/difference.ts b/src/fp/array/difference.ts new file mode 100644 index 000000000..c523527ce --- /dev/null +++ b/src/fp/array/difference.ts @@ -0,0 +1,57 @@ +import { difference as differenceToolkit } from '../../array/difference'; + +/** + * Computes the difference between two arrays. + * + * This function takes two arrays and returns a new array containing the elements + * that are present in the first array but not in the second array. It effectively + * filters out any elements from the first array that also appear in the second array. + * + * @template T + * @param {T[]} firstArr - The array from which to derive the difference. This is the primary array + * from which elements will be compared and filtered. + * @param {T[]} secondArr - The array containing elements to be excluded from the first array. + * Each element in this array will be checked against the first array, and if a match is found, + * that element will be excluded from the result. + * @returns {T[]} A new array containing the elements that are present in the first array but not + * in the second array. + * + * @example + * const array1 = [1, 2, 3, 4, 5]; + * const array2 = [2, 4]; + * const result = difference(array1, array2); + * // result will be [1, 3, 5] since 2 and 4 are in both arrays and are excluded from the result. + */ +export function difference(firstArr: readonly T[], secondArr: readonly T[]): T[]; + +/** + * Computes the difference between two arrays. + * + * This function takes two arrays and returns a new array containing the elements + * that are present in the first array but not in the second array. It effectively + * filters out any elements from the first array that also appear in the second array. + * + * @template T + * from which elements will be compared and filtered. + * @param {T[]} secondArr - The array containing elements to be excluded from the first array. + * Each element in this array will be checked against the first array, and if a match is found, + * that element will be excluded from the result. + * @returns {(firstArr: T[]) => T[]} A function that receive the array from which to derive the difference. This is the primary array as argument and returns a new array containing the elements that are present in the first array but not. + * in the second array. + * + * @example + * const array1 = [1, 2, 3, 4, 5]; + * const array2 = [2, 4]; + * const result = difference(array2)(array1); + * // result will be [1, 3, 5] since 2 and 4 are in both arrays and are excluded from the result. + */ +export function difference(secondArr: readonly T[]): (firstArr: readonly T[]) => T[]; + +export function difference(firstArrOrSecondArr: readonly T[] | readonly T[], secondArr?: readonly T[]) { + if (secondArr == null) { + return (firstArr: readonly T[]) => difference(firstArr, firstArrOrSecondArr as readonly T[]); + } + + const firstArr = firstArrOrSecondArr as readonly T[]; + return differenceToolkit(firstArr, secondArr); +} From d21a7190ed62ed961da688bfe50e30e6ba75e538 Mon Sep 17 00:00:00 2001 From: seungro Date: Tue, 19 Nov 2024 23:31:53 +0900 Subject: [PATCH 15/30] fix difference (fp) --- src/fp/array/difference.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fp/array/difference.ts b/src/fp/array/difference.ts index c523527ce..6ee56a022 100644 --- a/src/fp/array/difference.ts +++ b/src/fp/array/difference.ts @@ -32,7 +32,6 @@ export function difference(firstArr: readonly T[], secondArr: readonly T[]): * filters out any elements from the first array that also appear in the second array. * * @template T - * from which elements will be compared and filtered. * @param {T[]} secondArr - The array containing elements to be excluded from the first array. * Each element in this array will be checked against the first array, and if a match is found, * that element will be excluded from the result. From 745334e3f26325f34015b6b76ca2f5a12f5df391 Mon Sep 17 00:00:00 2001 From: seungro Date: Wed, 20 Nov 2024 14:43:11 +0900 Subject: [PATCH 16/30] feat. fix fp functions type (focus on usage with pipe) --- src/fp/array/at.spec.ts | 24 +++++----- src/fp/array/at.ts | 2 +- src/fp/array/chunk.spec.ts | 90 +++++++++++++++-------------------- src/fp/array/chunk.ts | 2 +- src/fp/array/compact.spec.ts | 24 ---------- src/fp/array/compact.ts | 25 ---------- src/fp/array/countBy.spec.ts | 4 +- src/fp/array/countBy.ts | 4 +- src/fp/object/mapKeys.spec.ts | 14 ++++-- src/fp/object/mapKeys.ts | 12 ++--- src/fp/object/omitBy.spec.ts | 4 +- src/fp/object/omitBy.ts | 39 ++++++++------- 12 files changed, 96 insertions(+), 148 deletions(-) delete mode 100644 src/fp/array/compact.spec.ts delete mode 100644 src/fp/array/compact.ts diff --git a/src/fp/array/at.spec.ts b/src/fp/array/at.spec.ts index 65fce3d58..47bc5fc9a 100644 --- a/src/fp/array/at.spec.ts +++ b/src/fp/array/at.spec.ts @@ -3,38 +3,38 @@ import { at } from './at'; describe('at', () => { it('(non-curried) should return the elements corresponding to the specified keys', () => { - expect(at(['a', 'b', 'c'], [0, 2])).toEqual(['a', 'c']); - expect(at(['a', 'b', 'c'], [2, 0])).toEqual(['c', 'a']); + expect(at(['a', 'b', 'c'], [0, 2])).toEqual(['a', 'c']); + expect(at(['a', 'b', 'c'], [2, 0])).toEqual(['c', 'a']); }); it('(curried) should return the elements corresponding to the specified keys', () => { - expect(at([0, 2])(['a', 'b', 'c'])).toEqual(['a', 'c']); - expect(at([2, 0])(['a', 'b', 'c'])).toEqual(['c', 'a']); + expect(at([0, 2])(['a', 'b', 'c'])).toEqual(['a', 'c']); + expect(at([2, 0])(['a', 'b', 'c'])).toEqual(['c', 'a']); }); it('(non-curried) should support negative indices', () => { - expect(at(['a', 'b', 'c'], [-1, -2])).toEqual(['c', 'b']); - expect(at(['a', 'b', 'c'], [-2, -1])).toEqual(['b', 'c']); + expect(at(['a', 'b', 'c'], [-1, -2])).toEqual(['c', 'b']); + expect(at(['a', 'b', 'c'], [-2, -1])).toEqual(['b', 'c']); }); it('(curried) should support negative indices', () => { - expect(at([-1, -2])(['a', 'b', 'c'])).toEqual(['c', 'b']); - expect(at([-2, -1])(['a', 'b', 'c'])).toEqual(['b', 'c']); + expect(at([-1, -2])(['a', 'b', 'c'])).toEqual(['c', 'b']); + expect(at([-2, -1])(['a', 'b', 'c'])).toEqual(['b', 'c']); }); it('(non-curried) should return `undefined` for nonexistent keys', () => { - expect(at(['a', 'b', 'c'], [2, 4, 0])).toEqual(['c', undefined, 'a']); + expect(at(['a', 'b', 'c'], [2, 4, 0])).toEqual(['c', undefined, 'a']); }); it('(curried) should return `undefined` for nonexistent keys', () => { - expect(at([2, 4, 0])(['a', 'b', 'c'])).toEqual(['c', undefined, 'a']); + expect(at([2, 4, 0])(['a', 'b', 'c'])).toEqual(['c', undefined, 'a']); }); it('(non-curried) should return an empty array when no keys are given', () => { - expect(at(['a', 'b', 'c'], [])).toEqual([]); + expect(at(['a', 'b', 'c'], [])).toEqual([]); }); it('(curried) should return an empty array when no keys are given', () => { - expect(at([])(['a', 'b', 'c'])).toEqual([]); + expect(at([])(['a', 'b', 'c'])).toEqual([]); }); }); diff --git a/src/fp/array/at.ts b/src/fp/array/at.ts index c440baa8e..73d4facc4 100644 --- a/src/fp/array/at.ts +++ b/src/fp/array/at.ts @@ -31,7 +31,7 @@ export function at(arr: readonly T[], indices: number[]): Array(arr: readonly T[]) => Array; +export function at(indices: number[]): (arr: readonly T[]) => Array; export function at(arrOrIndices: readonly T[] | number[], indices?: number[]) { if (indices == null) { diff --git a/src/fp/array/chunk.spec.ts b/src/fp/array/chunk.spec.ts index 48890a45e..97773b193 100644 --- a/src/fp/array/chunk.spec.ts +++ b/src/fp/array/chunk.spec.ts @@ -2,77 +2,65 @@ import { describe, expect, it } from 'vitest'; import { chunk } from './chunk'; describe('chunk', () => { - it( - "(non-curried) should return an empty array when the input array is empty", - () => { - expect(chunk([], 3)).toEqual([]); - } - ); + it('(non-curried) should return an empty array when the input array is empty', () => { + expect(chunk([], 3)).toEqual([]); + }); - it("(curried) should return an empty array when the input array is empty", () => { - expect(chunk(3)([])).toEqual([]); + it('(curried) should return an empty array when the input array is empty', () => { + expect(chunk(3)([])).toEqual([]); }); - it( - "(non-curried) should throw if the size is not an integer of is less than 1", - () => { - expect(() => chunk([1, 2, 3], 0)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - expect(() => chunk([1, 2, 3], -1)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - expect(() => chunk([1, 2, 3], 0.5)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - expect(() => chunk([1, 2, 3], Math.PI)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - } - ); + it('(non-curried) should throw if the size is not an integer of is less than 1', () => { + expect(() => chunk([1, 2, 3], 0)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], -1)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], 0.5)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], Math.PI)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + }); - it("(curried) should throw if the size is not an integer of is less than 1", () => { - expect(() => chunk(0)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + it('(curried) should throw if the size is not an integer of is less than 1', () => { + expect(() => chunk(0)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); - expect(() => chunk(-1)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + expect(() => chunk(-1)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); - expect(() => chunk(0.5)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + expect(() => chunk(0.5)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); - expect(() => chunk(Math.PI)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + expect(() => chunk(Math.PI)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); }); - it( - "(non-curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size", - () => { - expect(chunk([1, 2, 3, 4, 5, 6], 3)).toEqual([ - [1, 2, 3], - [4, 5, 6], - ]); - } - ); + it('(non-curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size', () => { + expect(chunk([1, 2, 3, 4, 5, 6], 3)).toEqual([ + [1, 2, 3], + [4, 5, 6], + ]); + }); - it("(curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size", () => { - expect(chunk(3)([1, 2, 3, 4, 5, 6])).toEqual([ + it('(curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size', () => { + expect(chunk(3)([1, 2, 3, 4, 5, 6])).toEqual([ [1, 2, 3], [4, 5, 6], ]); }); - it( - "(non-curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size", - () => { - expect(chunk([1, 2, 3, 4], 6)).toEqual([[1, 2, 3, 4]]); - expect(chunk([1, 2, 3, 4, 5, 6, 7], 2)).toEqual([[1, 2], [3, 4], [5, 6], [7]]); - } - ); + it('(non-curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size', () => { + expect(chunk([1, 2, 3, 4], 6)).toEqual([[1, 2, 3, 4]]); + expect(chunk([1, 2, 3, 4, 5, 6, 7], 2)).toEqual([[1, 2], [3, 4], [5, 6], [7]]); + }); - it("(curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size", () => { - expect(chunk(6)([1, 2, 3, 4])).toEqual([[1, 2, 3, 4]]); - expect(chunk(2)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2], [3, 4], [5, 6], [7]]); + it('(curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size', () => { + expect(chunk(6)([1, 2, 3, 4])).toEqual([[1, 2, 3, 4]]); + expect(chunk(2)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2], [3, 4], [5, 6], [7]]); }); }); diff --git a/src/fp/array/chunk.ts b/src/fp/array/chunk.ts index 934ef56cc..63413334a 100644 --- a/src/fp/array/chunk.ts +++ b/src/fp/array/chunk.ts @@ -47,7 +47,7 @@ export function chunk(arr: readonly T[], size: number): T[][]; * chunk(['a', 'b', 'c', 'd', 'e', 'f', 'g'], 3); * // Returns: [['a', 'b', 'c'], ['d', 'e', 'f'], ['g']] */ -export function chunk(size: number): (arr: readonly T[]) => T[][]; +export function chunk(size: number): (arr: readonly T[]) => T[][]; export function chunk(arrOrSize: readonly T[] | number, size?: number) { if (size == null) { diff --git a/src/fp/array/compact.spec.ts b/src/fp/array/compact.spec.ts deleted file mode 100644 index 01eac9619..000000000 --- a/src/fp/array/compact.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { compact } from './compact'; - -describe('compact', () => { - it("(non-curried) removes falsey values from array", () => { - expect(compact([0, 1, false, 2, '', 3, null, undefined, 4, NaN, 5])).toEqual([1, 2, 3, 4, 5]); - expect(compact([false, 0, '', null, undefined, NaN])).toEqual([]); - expect(compact([0, { name: 'John' }, false, 'hello', null, { age: 30 }, undefined, NaN])).toEqual([ - { name: 'John' }, - 'hello', - { age: 30 }, - ]); - }); - - it("(curried) removes falsey values from array", () => { - expect(compact()([0, 1, false, 2, '', 3, null, undefined, 4, NaN, 5])).toEqual([1, 2, 3, 4, 5]); - expect(compact()([false, 0, '', null, undefined, NaN])).toEqual([]); - expect(compact()([0, { name: 'John' }, false, 'hello', null, { age: 30 }, undefined, NaN])).toEqual([ - { name: 'John' }, - 'hello', - { age: 30 }, - ]); - }); -}); diff --git a/src/fp/array/compact.ts b/src/fp/array/compact.ts deleted file mode 100644 index 358dc7981..000000000 --- a/src/fp/array/compact.ts +++ /dev/null @@ -1,25 +0,0 @@ -type NotFalsey = Exclude; - -/** - * Removes falsey values (false, null, 0, 0n, '', undefined, NaN) from an array. - * - * @template T - The type of elements in the array. - * @param {T[]} arr - The input array to remove falsey values. - * @returns {Array>} - A new array with all falsey values removed. - * - * @example - * compact([0, 0n, 1, false, 2, '', 3, null, undefined, 4, NaN, 5]); - * Returns: [1, 2, 3, 4, 5] - */ -export function compact(arr: readonly T[]): Array> { - const result: Array> = []; - - for (let i = 0; i < arr.length; i++) { - const item = arr[i]; - if (item) { - result.push(item as NotFalsey); - } - } - - return result; -} diff --git a/src/fp/array/countBy.spec.ts b/src/fp/array/countBy.spec.ts index 310740915..c3e540c3b 100644 --- a/src/fp/array/countBy.spec.ts +++ b/src/fp/array/countBy.spec.ts @@ -17,7 +17,7 @@ describe('countBy', () => { it('(curried) should count the occurrences of each item in an array', () => { const arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]; - const result = countBy(String)(arr); + const result = countBy(String)(arr); expect(result).toEqual({ '1': 2, @@ -40,7 +40,7 @@ describe('countBy', () => { it('(curried) should count the occurrences of each item in an array that applied transformer', () => { const arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]; - const result = countBy((item: number) => (item % 2 === 0 ? 'even' : 'odd'))(arr); + const result = countBy(item => (item % 2 === 0 ? 'even' : 'odd'))(arr); expect(result).toEqual({ odd: 6, diff --git a/src/fp/array/countBy.ts b/src/fp/array/countBy.ts index bce367b7c..9e430a8ab 100644 --- a/src/fp/array/countBy.ts +++ b/src/fp/array/countBy.ts @@ -55,7 +55,9 @@ export function countBy(arr: readonly T[], mapper: (it * const result = countBy(array, item => item % 2 === 0 ? 'even' : 'odd'); * // result will be { odd: 3, even: 2 } */ -export function countBy(mapper: (item: T) => K): (arr: readonly T[]) => Record; +export function countBy( + mapper: (item: T) => K +): (arr: readonly T[]) => Record; export function countBy( arrOrMapper: readonly T[] | ((item: T) => K), diff --git a/src/fp/object/mapKeys.spec.ts b/src/fp/object/mapKeys.spec.ts index e30496b24..5b02dd35b 100644 --- a/src/fp/object/mapKeys.spec.ts +++ b/src/fp/object/mapKeys.spec.ts @@ -7,7 +7,11 @@ describe('mapKeys', () => { }); it('(curried) should iterate over and map the object using its own string keys', () => { - expect(mapKeys((_, key) => `${key}a`)({ a: 1, b: 2, c: 3 })).toEqual({ aa: 1, ba: 2, ca: 3 }); + expect(mapKeys>((_, key) => `${key}a`)({ a: 1, b: 2, c: 3 })).toEqual({ + aa: 1, + ba: 2, + ca: 3, + }); }); it('(non-curried) should iterate over and map the object using its own number keys', () => { @@ -15,7 +19,11 @@ describe('mapKeys', () => { }); it('(curried) should iterate over and map the object using its own number keys', () => { - expect(mapKeys((_, key: number) => key * 2)({ 1: 'a', 2: 'b', 3: 'c' })).toEqual({ 2: 'a', 4: 'b', 6: 'c' }); + expect(mapKeys>((_, key) => key * 2)({ 1: 'a', 2: 'b', 3: 'c' })).toEqual({ + 2: 'a', + 4: 'b', + 6: 'c', + }); }); it('(non-curried) should pass the value corresponding to the current key into the iteratee', () => { @@ -23,6 +31,6 @@ describe('mapKeys', () => { }); it('(curried) should pass the value corresponding to the current key into the iteratee', () => { - expect(mapKeys((value: number) => value)({ a: 1, b: 2, c: 3 })).toEqual({ 1: 1, 2: 2, 3: 3 }); + expect(mapKeys>(value => value)({ a: 1, b: 2, c: 3 })).toEqual({ 1: 1, 2: 2, 3: 3 }); }); }); diff --git a/src/fp/object/mapKeys.ts b/src/fp/object/mapKeys.ts index 6ce9c424c..37ead0d7f 100644 --- a/src/fp/object/mapKeys.ts +++ b/src/fp/object/mapKeys.ts @@ -27,12 +27,12 @@ export function mapKeys) => K2} getNewKey - The function invoked per own enumerable property. - * @returns {(object: Record) => Record} A function that receive the object to iterate over as argument and returns - Returns the new mapped object. + * @param {(value: T[K1], key: K1, object: T) => K2} getNewKey - The function invoked per own enumerable property. + * @returns {(object: T) => Record} A function that receive the object to iterate over as argument and returns - Returns the new mapped object. * * @example * // Example usage: @@ -40,9 +40,9 @@ export function mapKeys key + value)(obj); * console.log(result); // { a1: 1, b2: 2 } */ -export function mapKeys( - getNewKey: (value: V, key: K1, object: Record) => K2 -): (object: Record) => Record; +export function mapKeys( + getNewKey: (value: T[K1], key: K1, object: T) => K2 +): (object: T) => Record; export function mapKeys( objectOrGetNewKey: T | ((value: T[K1], key: K1, object: T) => K2), diff --git a/src/fp/object/omitBy.spec.ts b/src/fp/object/omitBy.spec.ts index 8350f5d94..b99748550 100644 --- a/src/fp/object/omitBy.spec.ts +++ b/src/fp/object/omitBy.spec.ts @@ -54,7 +54,7 @@ describe('omitBy', () => { it('(curried) should work with an empty object', () => { const obj = {}; const shouldOmit = (value: never) => value; - const result = omitBy(shouldOmit)(obj); + const result = omitBy<{}>(shouldOmit)(obj); expect(result).toEqual({}); }); @@ -68,7 +68,7 @@ describe('omitBy', () => { it('(curried) should work with nested objects', () => { const obj = { a: 1, b: { nested: 'omit' }, c: 3 }; const shouldOmit = (_: number | { nested: string }, key: string) => key === 'b'; - const result = omitBy(shouldOmit)(obj); + const result = omitBy(shouldOmit)(obj); expect(result).toEqual({ a: 1, c: 3 }); }); }); diff --git a/src/fp/object/omitBy.ts b/src/fp/object/omitBy.ts index 90e44b22a..9eab47d34 100644 --- a/src/fp/object/omitBy.ts +++ b/src/fp/object/omitBy.ts @@ -6,13 +6,12 @@ import { omitBy as omitByToolkit } from '../../object/omitBy'; * This function takes an object and a predicate function, and returns a new object that * includes only the properties for which the predicate function returns false. * - * @template T - The type of object value. - * @template O - The type of object. - * @param {O} obj - The object to omit properties from. - * @param {(value: T, key: keyof O) => boolean} shouldOmit - A predicate function that determines + * @template T - The type of object. + * @param {T} obj - The object to omit properties from. + * @param {(value: T[string], key: keyof T) => boolean} shouldOmit - A predicate function that determines * whether a property should be omitted. It takes the property's key and value as arguments and returns `true` * if the property should be omitted, and `false` otherwise. - * @returns {Partial} A new object with the properties that do not satisfy the predicate function. + * @returns {Partial} A new object with the properties that do not satisfy the predicate function. * * @example * const obj = { a: 1, b: 'omit', c: 3 }; @@ -20,10 +19,10 @@ import { omitBy as omitByToolkit } from '../../object/omitBy'; * const result = omitBy(obj, shouldOmit); * // result will be { a: 1, c: 3 } */ -export function omitBy>( - obj: O, - shouldOmit: (value: T, key: keyof O) => boolean -): Partial; +export function omitBy>( + obj: T, + shouldOmit: (value: T[keyof T], key: keyof T) => boolean +): Partial; /** * Creates a new object composed of the properties that do not satisfy the predicate function. @@ -31,11 +30,11 @@ export function omitBy>( * This function takes an object and a predicate function, and returns a new object that * includes only the properties for which the predicate function returns false. * - * @template T - The type of object value. - * @param {(value: T, key: string) => boolean} shouldOmit - A predicate function that determines + * @template T - The type of object. + * @param {(value: T[string], key: keyof T) => boolean} shouldOmit - A predicate function that determines * whether a property should be omitted. It takes the property's key and value as arguments and returns `true` * if the property should be omitted, and `false` otherwise. - * @returns {(obj: Record) => Partial} A function that receive the object to omit properties from as argument and returns a new object with the properties that do not satisfy the predicate function. + * @returns {(obj: T) => Partial} A function that receive the object to omit properties from as argument and returns a new object with the properties that do not satisfy the predicate function. * * @example * const obj = { a: 1, b: 'omit', c: 3 }; @@ -43,18 +42,18 @@ export function omitBy>( * const result = omitBy(shouldOmit)(obj); * // result will be { a: 1, c: 3 } */ -export function omitBy( - shouldOmit: (value: T, key: string) => boolean -): (obj: Record) => Partial>; +export function omitBy>( + shouldOmit: (value: T[keyof T], key: keyof T) => boolean +): (obj: T) => Partial; -export function omitBy>( - objOrShouldOmit: O | ((value: T, key: keyof O) => boolean), - shouldOmit?: (value: T, key: keyof O) => boolean +export function omitBy>( + objOrShouldOmit: T | ((value: T[keyof T], key: keyof T) => boolean), + shouldOmit?: (value: T[keyof T], key: keyof T) => boolean ) { if (shouldOmit == null) { - return (obj: O) => omitBy(obj, objOrShouldOmit as (value: T, key: keyof O) => boolean); + return (obj: T) => omitBy(obj, objOrShouldOmit as (value: T[keyof T], key: keyof T) => boolean); } - const obj = objOrShouldOmit as O; + const obj = objOrShouldOmit as T; return omitByToolkit(obj, shouldOmit); } From 3d131ac8508bf9bf6b25edbd97951208845aa119 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 10:41:03 +0900 Subject: [PATCH 17/30] fix test codes --- src/fp/array/chunk.spec.ts | 90 +++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/src/fp/array/chunk.spec.ts b/src/fp/array/chunk.spec.ts index 97773b193..48890a45e 100644 --- a/src/fp/array/chunk.spec.ts +++ b/src/fp/array/chunk.spec.ts @@ -2,65 +2,77 @@ import { describe, expect, it } from 'vitest'; import { chunk } from './chunk'; describe('chunk', () => { - it('(non-curried) should return an empty array when the input array is empty', () => { - expect(chunk([], 3)).toEqual([]); - }); + it( + "(non-curried) should return an empty array when the input array is empty", + () => { + expect(chunk([], 3)).toEqual([]); + } + ); - it('(curried) should return an empty array when the input array is empty', () => { - expect(chunk(3)([])).toEqual([]); + it("(curried) should return an empty array when the input array is empty", () => { + expect(chunk(3)([])).toEqual([]); }); - it('(non-curried) should throw if the size is not an integer of is less than 1', () => { - expect(() => chunk([1, 2, 3], 0)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - expect(() => chunk([1, 2, 3], -1)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - expect(() => chunk([1, 2, 3], 0.5)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - expect(() => chunk([1, 2, 3], Math.PI)).toThrowErrorMatchingInlineSnapshot( - `[Error: Size must be an integer greater than zero.]` - ); - }); + it( + "(non-curried) should throw if the size is not an integer of is less than 1", + () => { + expect(() => chunk([1, 2, 3], 0)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], -1)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], 0.5)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + expect(() => chunk([1, 2, 3], Math.PI)).toThrowErrorMatchingInlineSnapshot( + `[Error: Size must be an integer greater than zero.]` + ); + } + ); - it('(curried) should throw if the size is not an integer of is less than 1', () => { - expect(() => chunk(0)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + it("(curried) should throw if the size is not an integer of is less than 1", () => { + expect(() => chunk(0)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); - expect(() => chunk(-1)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + expect(() => chunk(-1)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); - expect(() => chunk(0.5)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + expect(() => chunk(0.5)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); - expect(() => chunk(Math.PI)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( + expect(() => chunk(Math.PI)([1, 2, 3])).toThrowErrorMatchingInlineSnapshot( `[Error: Size must be an integer greater than zero.]` ); }); - it('(non-curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size', () => { - expect(chunk([1, 2, 3, 4, 5, 6], 3)).toEqual([ - [1, 2, 3], - [4, 5, 6], - ]); - }); + it( + "(non-curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size", + () => { + expect(chunk([1, 2, 3, 4, 5, 6], 3)).toEqual([ + [1, 2, 3], + [4, 5, 6], + ]); + } + ); - it('(curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size', () => { - expect(chunk(3)([1, 2, 3, 4, 5, 6])).toEqual([ + it("(curried) should evenly divide all elements into chunks of the specified size when the total length is a multiple of the size", () => { + expect(chunk(3)([1, 2, 3, 4, 5, 6])).toEqual([ [1, 2, 3], [4, 5, 6], ]); }); - it('(non-curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size', () => { - expect(chunk([1, 2, 3, 4], 6)).toEqual([[1, 2, 3, 4]]); - expect(chunk([1, 2, 3, 4, 5, 6, 7], 2)).toEqual([[1, 2], [3, 4], [5, 6], [7]]); - }); + it( + "(non-curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size", + () => { + expect(chunk([1, 2, 3, 4], 6)).toEqual([[1, 2, 3, 4]]); + expect(chunk([1, 2, 3, 4, 5, 6, 7], 2)).toEqual([[1, 2], [3, 4], [5, 6], [7]]); + } + ); - it('(curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size', () => { - expect(chunk(6)([1, 2, 3, 4])).toEqual([[1, 2, 3, 4]]); - expect(chunk(2)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2], [3, 4], [5, 6], [7]]); + it("(curried) should place the remaining elements in the last chunk when the total length is not a multiple of the size", () => { + expect(chunk(6)([1, 2, 3, 4])).toEqual([[1, 2, 3, 4]]); + expect(chunk(2)([1, 2, 3, 4, 5, 6, 7])).toEqual([[1, 2], [3, 4], [5, 6], [7]]); }); }); From a5ae2cad5e3769883685c12ed3012e3f968be237 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 10:48:16 +0900 Subject: [PATCH 18/30] feat. work with filter --- src/fp/array/filter.spec.ts | 39 ++++++++++++++++++++++++++++++ src/fp/array/filter.ts | 47 +++++++++++++++++++++++++++++++++++++ src/fp/array/map.ts | 2 -- 3 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 src/fp/array/filter.spec.ts create mode 100644 src/fp/array/filter.ts diff --git a/src/fp/array/filter.spec.ts b/src/fp/array/filter.spec.ts new file mode 100644 index 000000000..87f4881e3 --- /dev/null +++ b/src/fp/array/filter.spec.ts @@ -0,0 +1,39 @@ +import { describe, expect, it } from 'vitest'; +import { filter } from './filter'; + +describe('filter', () => { + const arr = [1, 2, 3, 4, 5]; + const isEven = (value: number) => value % 2 === 0; + + describe('when called with array and predicate', () => { + it('should filter array values by predicate', () => { + const result = filter(arr, isEven); + expect(result).toEqual([2, 4]); + }); + + it('should return empty array when no values match predicate', () => { + const result = filter(arr, value => value > 10); + expect(result).toEqual([]); + }); + + it('should return same array when all values match predicate', () => { + const result = filter(arr, value => value > 0); + expect(result).toEqual(arr); + }); + }); + + describe('when called with predicate only', () => { + it('should return a function that filters array values', () => { + const filterEven = filter(isEven); + const result = filterEven(arr); + expect(result).toEqual([2, 4]); + }); + + it('should maintain curried function behavior', () => { + const greaterThan = (min: number) => filter((value: number) => value > min); + const greaterThan3 = greaterThan(3); + const result = greaterThan3(arr); + expect(result).toEqual([4, 5]); + }); + }); +}); diff --git a/src/fp/array/filter.ts b/src/fp/array/filter.ts new file mode 100644 index 000000000..989d9f4d3 --- /dev/null +++ b/src/fp/array/filter.ts @@ -0,0 +1,47 @@ +export function filter(predicate: (value: T[number]) => boolean): (arr: T) => T[number][]; +/** + * Filter array values by predicate function. + * + * @template T - The type of array. + * @param {T} arr - The array to be filtered. + * @param {(value: T[number]) => boolean} predicate - The function that tests each item. + * @returns {T[number][]} A new array with filtered values. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const result = filter(arr, value => value % 2 === 0); + * // result will be [2, 4] + */ +export function filter(arr: T, predicate: (value: T[number]) => boolean): T[number][]; +/** + * Filter array values by predicate function. + * + * @template T - The type of array. + * @param {(value: T[number]) => boolean} predicate - The function that tests each item. + * @returns {(arr: T) => T[number][]} A function that takes an array and returns filtered values. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const isEven = filter(value => value % 2 === 0); + * const result = isEven(arr); + * // result will be [2, 4] + */ +export function filter( + arrOrPredicate: T | ((value: T[number]) => boolean), + predicate?: (value: T[number]) => boolean +) { + if (predicate == null) { + return (arr: T) => filter(arr, arrOrPredicate as (value: T[number]) => boolean); + } + + const arr = arrOrPredicate as T[]; + const result = []; + + for (const item of arr) { + if (predicate(item)) { + result.push(item); + } + } + + return result; +} diff --git a/src/fp/array/map.ts b/src/fp/array/map.ts index 002b25d49..93d8b1da9 100644 --- a/src/fp/array/map.ts +++ b/src/fp/array/map.ts @@ -1,5 +1,3 @@ -import { pipe } from '../core/pipe'; - export function map(mapper: (value: T[number]) => R): (arr: T) => R[]; /** * Map each values of array by mapper function. From 120e9cbc8b25daf11e52c3418e65af74e8a67154 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 10:59:12 +0900 Subject: [PATCH 19/30] feat. add fp/flatMap --- src/fp/array/flatMap.spec.ts | 38 +++++++++++++++++++++++++++++++ src/fp/array/flatMap.ts | 43 ++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 src/fp/array/flatMap.spec.ts create mode 100644 src/fp/array/flatMap.ts diff --git a/src/fp/array/flatMap.spec.ts b/src/fp/array/flatMap.spec.ts new file mode 100644 index 000000000..590c28944 --- /dev/null +++ b/src/fp/array/flatMap.spec.ts @@ -0,0 +1,38 @@ +import { describe, expect, it } from 'vitest'; +import { flatMap } from './flatMap'; + +describe('flatMap', () => { + it('(non-curried) should map and flatten array values', () => { + expect(flatMap([1, 2, 3], x => [x, x * 2])).toEqual([1, 2, 2, 4, 3, 6]); + expect(flatMap(['a', 'b'], x => [x, x])).toEqual(['a', 'a', 'b', 'b']); + }); + + it('(curried) should map and flatten array values', () => { + expect(flatMap((x: number) => [x, x * 2])([1, 2, 3])).toEqual([1, 2, 2, 4, 3, 6]); + expect(flatMap((x: string) => [x, x])(['a', 'b'])).toEqual(['a', 'a', 'b', 'b']); + }); + + it('(non-curried) should handle empty arrays', () => { + expect(flatMap([], x => [x, x])).toEqual([]); + }); + + it('(curried) should handle empty arrays', () => { + expect(flatMap((x: number) => [x, x])([])).toEqual([]); + }); + + it('(non-curried) should handle empty result arrays', () => { + expect(flatMap([1, 2, 3], () => [])).toEqual([]); + }); + + it('(curried) should handle empty result arrays', () => { + expect(flatMap(() => [])([1, 2, 3])).toEqual([]); + }); + + it('(non-curried) should handle nested arrays', () => { + expect(flatMap([1, 2], x => [[x, x]])).toEqual([[1, 1], [2, 2]]); + }); + + it('(curried) should handle nested arrays', () => { + expect(flatMap((x: number) => [[x, x]])([1, 2])).toEqual([[1, 1], [2, 2]]); + }); +}); \ No newline at end of file diff --git a/src/fp/array/flatMap.ts b/src/fp/array/flatMap.ts new file mode 100644 index 000000000..f7b8a177b --- /dev/null +++ b/src/fp/array/flatMap.ts @@ -0,0 +1,43 @@ +import { flatMap as flatMapToolkit } from '../../array/flatMap'; + +export function flatMap(mapper: (value: T[number]) => R[]): (arr: T) => R[]; +/** + * Map each values of array by mapper function and flatten the result. + * + * @template T - The type of array. + * @template R - The type of mapped value. + * @param {T} arr - The array to be mapped. + * @param {(value: T[number]) => R[]} mapper - The function that map each items to array of new values. + * @returns {R[]} A new flattened array with mapped values. + * + * @example + * const arr = [1, 2, 3]; + * const result = flatMap(arr, value => [value, value * 2]); + * // result will be [1, 2, 2, 4, 3, 6] + */ +export function flatMap(arr: T, mapper: (value: T[number]) => R[]): R[]; +/** + * Map each values of array by mapper function and flatten the result. + * + * @template T - The type of array. + * @template R - The type of mapped value. + * @param {(value: T[number]) => R[]} mapper - The function that map each items to array of new values. + * @returns {(arr: T) => R[]} A function that takes an array and returns flattened mapped values. + * + * @example + * const arr = [1, 2, 3]; + * const duplicate = flatMap(value => [value, value]); + * const result = duplicate(arr); + * // result will be [1, 1, 2, 2, 3, 3] + */ +export function flatMap( + arrOrMapper: T | ((value: T[number]) => R[]), + mapper?: (value: T[number]) => R[] +) { + if (mapper == null) { + return (arr: T) => flatMap(arr, arrOrMapper as (value: T[number]) => R[]); + } + + const arr = arrOrMapper as T[]; + return flatMapToolkit(arr, mapper as any); +} From b0f1601a2d98866015d63dd3cf17d1b4a868cb61 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 11:41:49 +0900 Subject: [PATCH 20/30] feat. add fp/slice --- src/fp/array/filter.ts | 17 ++++++++-------- src/fp/array/flatMap.ts | 21 ++++++++++---------- src/fp/array/map.ts | 17 ++++++++-------- src/fp/array/slice.spec.ts | 30 ++++++++++++++++++++++++++++ src/fp/array/slice.ts | 40 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 26 deletions(-) create mode 100644 src/fp/array/slice.spec.ts create mode 100644 src/fp/array/slice.ts diff --git a/src/fp/array/filter.ts b/src/fp/array/filter.ts index 989d9f4d3..85ecd4f0d 100644 --- a/src/fp/array/filter.ts +++ b/src/fp/array/filter.ts @@ -1,31 +1,32 @@ -export function filter(predicate: (value: T[number]) => boolean): (arr: T) => T[number][]; /** * Filter array values by predicate function. * * @template T - The type of array. - * @param {T} arr - The array to be filtered. * @param {(value: T[number]) => boolean} predicate - The function that tests each item. - * @returns {T[number][]} A new array with filtered values. + * @returns {(arr: T) => T[number][]} A function that takes an array and returns filtered values. * * @example * const arr = [1, 2, 3, 4, 5]; - * const result = filter(arr, value => value % 2 === 0); + * const isEven = filter(value => value % 2 === 0); + * const result = isEven(arr); * // result will be [2, 4] */ -export function filter(arr: T, predicate: (value: T[number]) => boolean): T[number][]; +export function filter(predicate: (value: T[number]) => boolean): (arr: T) => T[number][]; /** * Filter array values by predicate function. * * @template T - The type of array. + * @param {T} arr - The array to be filtered. * @param {(value: T[number]) => boolean} predicate - The function that tests each item. - * @returns {(arr: T) => T[number][]} A function that takes an array and returns filtered values. + * @returns {T[number][]} A new array with filtered values. * * @example * const arr = [1, 2, 3, 4, 5]; - * const isEven = filter(value => value % 2 === 0); - * const result = isEven(arr); + * const result = filter(arr, value => value % 2 === 0); * // result will be [2, 4] */ +export function filter(arr: T, predicate: (value: T[number]) => boolean): T[number][]; + export function filter( arrOrPredicate: T | ((value: T[number]) => boolean), predicate?: (value: T[number]) => boolean diff --git a/src/fp/array/flatMap.ts b/src/fp/array/flatMap.ts index f7b8a177b..88be287e5 100644 --- a/src/fp/array/flatMap.ts +++ b/src/fp/array/flatMap.ts @@ -1,35 +1,36 @@ import { flatMap as flatMapToolkit } from '../../array/flatMap'; -export function flatMap(mapper: (value: T[number]) => R[]): (arr: T) => R[]; /** * Map each values of array by mapper function and flatten the result. * * @template T - The type of array. * @template R - The type of mapped value. - * @param {T} arr - The array to be mapped. * @param {(value: T[number]) => R[]} mapper - The function that map each items to array of new values. - * @returns {R[]} A new flattened array with mapped values. + * @returns {(arr: T) => R[]} A function that takes an array and returns flattened mapped values. * * @example * const arr = [1, 2, 3]; - * const result = flatMap(arr, value => [value, value * 2]); - * // result will be [1, 2, 2, 4, 3, 6] + * const duplicate = flatMap(value => [value, value]); + * const result = duplicate(arr); + * // result will be [1, 1, 2, 2, 3, 3] */ -export function flatMap(arr: T, mapper: (value: T[number]) => R[]): R[]; +export function flatMap(mapper: (value: T[number]) => R[]): (arr: T) => R[]; /** * Map each values of array by mapper function and flatten the result. * * @template T - The type of array. * @template R - The type of mapped value. + * @param {T} arr - The array to be mapped. * @param {(value: T[number]) => R[]} mapper - The function that map each items to array of new values. - * @returns {(arr: T) => R[]} A function that takes an array and returns flattened mapped values. + * @returns {R[]} A new flattened array with mapped values. * * @example * const arr = [1, 2, 3]; - * const duplicate = flatMap(value => [value, value]); - * const result = duplicate(arr); - * // result will be [1, 1, 2, 2, 3, 3] + * const result = flatMap(arr, value => [value, value * 2]); + * // result will be [1, 2, 2, 4, 3, 6] */ +export function flatMap(arr: T, mapper: (value: T[number]) => R[]): R[]; + export function flatMap( arrOrMapper: T | ((value: T[number]) => R[]), mapper?: (value: T[number]) => R[] diff --git a/src/fp/array/map.ts b/src/fp/array/map.ts index 93d8b1da9..14f3d80c4 100644 --- a/src/fp/array/map.ts +++ b/src/fp/array/map.ts @@ -1,33 +1,34 @@ -export function map(mapper: (value: T[number]) => R): (arr: T) => R[]; /** * Map each values of array by mapper function. * * @template T - The type of array. * @template R - The type of mapped value. - * @param {T} arr - The array to be mapped. * @param {(value: T[number]) => R} mapper - The function that map each items to new value. - * @returns {R[]} A new array with mapped values. + * @returns {(arr: T) => R[]} A new array with mapped values. * * @example * const arr = [1, 2, 3]; - * const result = map(arr, value => value * 2); + * const double = map(value => value * 2); + * const result = double(arr); * // result will be [2, 4, 6] */ -export function map(arr: T, mapper: (value: T[number]) => R): R[]; +export function map(mapper: (value: T[number]) => R): (arr: T) => R[]; /** * Map each values of array by mapper function. * * @template T - The type of array. * @template R - The type of mapped value. + * @param {T} arr - The array to be mapped. * @param {(value: T[number]) => R} mapper - The function that map each items to new value. - * @returns {(arr: T) => R[]} A new array with mapped values. + * @returns {R[]} A new array with mapped values. * * @example * const arr = [1, 2, 3]; - * const double = map(value => value * 2); - * const result = double(arr); + * const result = map(arr, value => value * 2); * // result will be [2, 4, 6] */ +export function map(arr: T, mapper: (value: T[number]) => R): R[]; + export function map( arrOrMapper: T | ((value: T[number]) => R), mapper?: (value: T[number]) => R diff --git a/src/fp/array/slice.spec.ts b/src/fp/array/slice.spec.ts new file mode 100644 index 000000000..bcc920424 --- /dev/null +++ b/src/fp/array/slice.spec.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from 'vitest'; +import { slice } from './slice'; + +describe('slice', () => { + it('should return sliced array with start and end indices', () => { + expect(slice([1, 2, 3, 4, 5], 1, 3)).toEqual([2, 3]); + expect(slice(1, 3)([1, 2, 3, 4, 5])).toEqual([2, 3]); + }); + + it('should handle negative indices', () => { + expect(slice([1, 2, 3, 4, 5], -2)).toEqual([4, 5]); + expect(slice(-2)([1, 2, 3, 4, 5])).toEqual([4, 5]); + }); + + it('should handle omitted end index', () => { + expect(slice([1, 2, 3, 4, 5], 2)).toEqual([3, 4, 5]); + expect(slice(2)([1, 2, 3, 4, 5])).toEqual([3, 4, 5]); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3, 4, 5]; + const arr2 = [1, 2, 3, 4, 5]; + + slice(arr, 1, 3); + slice(1, 3)(arr2); + + expect(arr).toEqual([1, 2, 3, 4, 5]); + expect(arr2).toEqual([1, 2, 3, 4, 5]); + }); +}); diff --git a/src/fp/array/slice.ts b/src/fp/array/slice.ts new file mode 100644 index 000000000..95b49ba04 --- /dev/null +++ b/src/fp/array/slice.ts @@ -0,0 +1,40 @@ +/** + * Creates a slice of array from start up to end. + * + * @template T - The type of array. + * @param {number} [start=0] - The start position. Negative index counts from the end. + * @param {number} [end=array.length] - The end position. Negative index counts from the end. + * @returns {(arr: T) => T[number][]} A function that takes an array and returns sliced elements. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const getFirstThree = slice(0, 3); + * const result = getFirstThree(arr); + * // result will be [1, 2, 3] + */ +export function slice(start: number, end?: number): (arr: T) => T[number][]; +/** + * Creates a slice of array from start up to end. + * + * @template T - The type of array. + * @param {T} arr - The array to slice. + * @param {number} [start=0] - The start position. Negative index counts from the end. + * @param {number} [end=array.length] - The end position. Negative index counts from the end. + * @returns {T[number][]} A new array with extracted elements. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const result = slice(arr, 1, 3); + * // result will be [2, 3] + */ +export function slice(arr: T, startOrEnd: number, end?: number): T[number][]; + +export function slice(arrOrStart: T | number, startOrEnd?: number, end?: number) { + if (!Array.isArray(arrOrStart)) { + return (arr: T) => slice(arr, arrOrStart, startOrEnd); + } + + const arr = arrOrStart; + + return arr.slice(startOrEnd, end); +} From 3d6a68e3744c9c8d73d8ca6e49132555243764b3 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 11:48:48 +0900 Subject: [PATCH 21/30] feat. add fp/every --- src/fp/array/every.spec.ts | 35 ++++++++++++++++++++++++++++ src/fp/array/every.ts | 47 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/fp/array/every.spec.ts create mode 100644 src/fp/array/every.ts diff --git a/src/fp/array/every.spec.ts b/src/fp/array/every.spec.ts new file mode 100644 index 000000000..7ad575b4f --- /dev/null +++ b/src/fp/array/every.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; +import { every } from './every'; + +describe('every', () => { + it('should return true when all elements pass the test', () => { + expect(every([2, 4, 6, 8], value => value % 2 === 0)).toBe(true); + expect(every(value => value % 2 === 0)([2, 4, 6, 8])).toBe(true); + }); + + it('should return false when any element fails the test', () => { + expect(every([1, 2, 3, 4], value => value % 2 === 0)).toBe(false); + expect(every(value => value % 2 === 0)([1, 2, 3, 4])).toBe(false); + }); + + it('should handle empty arrays', () => { + expect(every([], () => false)).toBe(true); + expect(every(() => false)([])).toBe(true); + }); + + it('should work with different types', () => { + expect(every(['a', 'ab', 'abc'], str => str.length > 0)).toBe(true); + expect(every(str => str.length > 0)(['a', 'ab', 'abc'])).toBe(true); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3, 4]; + const arr2 = [1, 2, 3, 4]; + + every(arr, value => value > 0); + every(value => value > 0)(arr2); + + expect(arr).toEqual([1, 2, 3, 4]); + expect(arr2).toEqual([1, 2, 3, 4]); + }); +}); diff --git a/src/fp/array/every.ts b/src/fp/array/every.ts new file mode 100644 index 000000000..7102e5b07 --- /dev/null +++ b/src/fp/array/every.ts @@ -0,0 +1,47 @@ +/** + * Tests whether all elements in the array pass the test implemented by the provided function. + * + * @template T - The type of array. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {(arr: T) => boolean} A function that takes an array and returns whether all elements pass the test. + * + * @example + * const arr = [2, 4, 6, 8]; + * const isEven = every(value => value % 2 === 0); + * const result = isEven(arr); + * // result will be true + */ +export function every(predicate: (value: T[number]) => boolean): (arr: T) => boolean; +/** + * Tests whether all elements in the array pass the test implemented by the provided function. + * + * @template T - The type of array. + * @param {T} arr - The array to test. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {boolean} Whether all elements in the array pass the test. + * + * @example + * const arr = [2, 4, 6, 8]; + * const result = every(arr, value => value % 2 === 0); + * // result will be true + */ +export function every(arr: T, predicate: (value: T[number]) => boolean): boolean; + +export function every( + arrOrPredicate: T | ((value: T[number]) => boolean), + predicate?: (value: T[number]) => boolean +) { + if (predicate == null) { + return (arr: T) => every(arr, arrOrPredicate as (value: T[number]) => boolean); + } + + const arr = arrOrPredicate as T[]; + + for (const item of arr) { + if (!predicate(item)) { + return false; + } + } + + return true; +} From 4c5d051526dae5abb7ed2389a4773bd03791a280 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 12:17:03 +0900 Subject: [PATCH 22/30] add fp/find --- src/fp/array/find.spec.ts | 35 +++++++++++++++++++++++++++++ src/fp/array/find.ts | 47 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/fp/array/find.spec.ts create mode 100644 src/fp/array/find.ts diff --git a/src/fp/array/find.spec.ts b/src/fp/array/find.spec.ts new file mode 100644 index 000000000..8eef00782 --- /dev/null +++ b/src/fp/array/find.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; +import { find } from './find'; + +describe('find', () => { + it('should return the first element that passes the test', () => { + expect(find([1, 2, 3, 4], value => value % 2 === 0)).toBe(2); + expect(find(value => value % 2 === 0)([1, 2, 3, 4])).toBe(2); + }); + + it('should return undefined when no element passes the test', () => { + expect(find([1, 3, 5, 7], value => value % 2 === 0)).toBeUndefined(); + expect(find(value => value % 2 === 0)([1, 3, 5, 7])).toBeUndefined(); + }); + + it('should handle empty arrays', () => { + expect(find([], () => true)).toBeUndefined(); + expect(find(() => true)([])).toBeUndefined(); + }); + + it('should work with different types', () => { + expect(find(['abc', 'def', 'ghi'], str => str.startsWith('d'))).toBe('def'); + expect(find(str => str.startsWith('d'))(['abc', 'def', 'ghi'])).toBe('def'); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3, 4]; + const arr2 = [1, 2, 3, 4]; + + find(arr, value => value > 2); + find(value => value > 2)(arr2); + + expect(arr).toEqual([1, 2, 3, 4]); + expect(arr2).toEqual([1, 2, 3, 4]); + }); +}); diff --git a/src/fp/array/find.ts b/src/fp/array/find.ts new file mode 100644 index 000000000..55a7e3692 --- /dev/null +++ b/src/fp/array/find.ts @@ -0,0 +1,47 @@ +/** + * Returns the first element in the array that satisfies the provided testing function. + * + * @template T - The type of array. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {(arr: T) => T[number] | undefined} A function that takes an array and returns the first element that satisfies the test, or undefined if no element is found. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const findFirstEven = find(value => value % 2 === 0); + * const result = findFirstEven(arr); + * // result will be 2 + */ +export function find(predicate: (value: T[number]) => boolean): (arr: T) => T[number] | undefined; +/** + * Returns the first element in the array that satisfies the provided testing function. + * + * @template T - The type of array. + * @param {T} arr - The array to search. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {T[number] | undefined} The first element that satisfies the test, or undefined if no element is found. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const result = find(arr, value => value % 2 === 0); + * // result will be 2 + */ +export function find(arr: T, predicate: (value: T[number]) => boolean): T[number] | undefined; + +export function find( + arrOrPredicate: T | ((value: T[number]) => boolean), + predicate?: (value: T[number]) => boolean +) { + if (predicate == null) { + return (arr: T) => find(arr, arrOrPredicate as (value: T[number]) => boolean); + } + + const arr = arrOrPredicate as T[]; + + for (const item of arr) { + if (predicate(item)) { + return item; + } + } + + return undefined; +} From 061b90c2a8b4c09aa879d3243d47081c1d233b44 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 12:19:21 +0900 Subject: [PATCH 23/30] add fp/findIndex --- src/fp/array/findIndex.spec.ts | 35 +++++++++++++++++++++++++ src/fp/array/findIndex.ts | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 src/fp/array/findIndex.spec.ts create mode 100644 src/fp/array/findIndex.ts diff --git a/src/fp/array/findIndex.spec.ts b/src/fp/array/findIndex.spec.ts new file mode 100644 index 000000000..36232b308 --- /dev/null +++ b/src/fp/array/findIndex.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; +import { findIndex } from './findIndex'; + +describe('findIndex', () => { + it('should return the index of first element that passes the test', () => { + expect(findIndex([1, 2, 3, 4], value => value % 2 === 0)).toBe(1); + expect(findIndex(value => value % 2 === 0)([1, 2, 3, 4])).toBe(1); + }); + + it('should return -1 when no element passes the test', () => { + expect(findIndex([1, 3, 5, 7], value => value % 2 === 0)).toBe(-1); + expect(findIndex(value => value % 2 === 0)([1, 3, 5, 7])).toBe(-1); + }); + + it('should handle empty arrays', () => { + expect(findIndex([], () => true)).toBe(-1); + expect(findIndex(() => true)([])).toBe(-1); + }); + + it('should work with different types', () => { + expect(findIndex(['abc', 'def', 'ghi'], str => str.startsWith('d'))).toBe(1); + expect(findIndex(str => str.startsWith('d'))(['abc', 'def', 'ghi'])).toBe(1); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3, 4]; + const arr2 = [1, 2, 3, 4]; + + findIndex(arr, value => value > 2); + findIndex(value => value > 2)(arr2); + + expect(arr).toEqual([1, 2, 3, 4]); + expect(arr2).toEqual([1, 2, 3, 4]); + }); +}); diff --git a/src/fp/array/findIndex.ts b/src/fp/array/findIndex.ts new file mode 100644 index 000000000..e36d41da5 --- /dev/null +++ b/src/fp/array/findIndex.ts @@ -0,0 +1,47 @@ +/** + * Returns the index of the first element in the array that satisfies the provided testing function. + * + * @template T - The type of array. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {(arr: T) => number} A function that takes an array and returns the index of the first element that satisfies the test, or -1 if no element is found. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const findFirstEvenIndex = findIndex(value => value % 2 === 0); + * const result = findFirstEvenIndex(arr); + * // result will be 1 + */ +export function findIndex(predicate: (value: T[number]) => boolean): (arr: T) => number; +/** + * Returns the index of the first element in the array that satisfies the provided testing function. + * + * @template T - The type of array. + * @param {T} arr - The array to search. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {number} The index of the first element that satisfies the test, or -1 if no element is found. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const result = findIndex(arr, value => value % 2 === 0); + * // result will be 1 + */ +export function findIndex(arr: T, predicate: (value: T[number]) => boolean): number; + +export function findIndex( + arrOrPredicate: T | ((value: T[number]) => boolean), + predicate?: (value: T[number]) => boolean +) { + if (predicate == null) { + return (arr: T) => findIndex(arr, arrOrPredicate as (value: T[number]) => boolean); + } + + const arr = arrOrPredicate as T[]; + + for (let i = 0; i < arr.length; i++) { + if (predicate(arr[i])) { + return i; + } + } + + return -1; +} From e466c2d74ef900974bcd8c764dd13b530e463ce7 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 12:23:30 +0900 Subject: [PATCH 24/30] add fp/includes --- src/fp/array/includes.spec.ts | 35 +++++++++++++++++++++++++++++++++ src/fp/array/includes.ts | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 src/fp/array/includes.spec.ts create mode 100644 src/fp/array/includes.ts diff --git a/src/fp/array/includes.spec.ts b/src/fp/array/includes.spec.ts new file mode 100644 index 000000000..182b1e468 --- /dev/null +++ b/src/fp/array/includes.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; +import { includes } from './includes'; + +describe('includes', () => { + it('should return true when element exists in array', () => { + expect(includes([1, 2, 3, 4], 2)).toBe(true); + expect(includes(2)([1, 2, 3, 4])).toBe(true); + }); + + it('should return false when element does not exist in array', () => { + expect(includes([1, 2, 3, 4], 5)).toBe(false); + expect(includes(5)([1, 2, 3, 4])).toBe(false); + }); + + it('should handle empty arrays', () => { + expect(includes([], 1)).toBe(false); + expect(includes(1)([])).toBe(false); + }); + + it('should work with different types', () => { + expect(includes(['a', 'b', 'c'], 'b')).toBe(true); + expect(includes('b')(['a', 'b', 'c'])).toBe(true); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3, 4]; + const arr2 = [1, 2, 3, 4]; + + includes(arr, 2); + includes(2)(arr2); + + expect(arr).toEqual([1, 2, 3, 4]); + expect(arr2).toEqual([1, 2, 3, 4]); + }); +}); diff --git a/src/fp/array/includes.ts b/src/fp/array/includes.ts new file mode 100644 index 000000000..1e904d719 --- /dev/null +++ b/src/fp/array/includes.ts @@ -0,0 +1,37 @@ +/** + * Determines whether an array includes a certain value. + * + * @template T - The type of array. + * @param {T[number]} searchElement - The value to search for. + * @returns {(arr: T) => boolean} A function that takes an array and returns whether the array includes the search element. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const hasTwo = includes(2); + * const result = hasTwo(arr); + * // result will be true + */ +export function includes(searchElement: T[number]): (arr: T) => boolean; +/** + * Determines whether an array includes a certain value. + * + * @template T - The type of array. + * @param {T} arr - The array to search in. + * @param {T[number]} searchElement - The value to search for. + * @returns {boolean} Whether the array includes the search element. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const result = includes(arr, 2); + * // result will be true + */ +export function includes(arr: T, searchElement: T[number]): boolean; + +export function includes(arrOrSearchElement: T | T[number], searchElement?: T[number]) { + if (searchElement === undefined && !Array.isArray(arrOrSearchElement)) { + return (arr: T) => includes(arr, arrOrSearchElement); + } + + const arr = arrOrSearchElement as T; + return arr.includes(searchElement as T[number]); +} From d1c28b2fb9daf48d5ebc6bc6a7e9c7b2bc21409e Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 14:11:40 +0900 Subject: [PATCH 25/30] feat add fp/join --- src/fp/array/join.spec.ts | 37 +++++++++++++++++++++++++++++++++++++ src/fp/array/join.ts | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 src/fp/array/join.spec.ts create mode 100644 src/fp/array/join.ts diff --git a/src/fp/array/join.spec.ts b/src/fp/array/join.spec.ts new file mode 100644 index 000000000..a0ec7973d --- /dev/null +++ b/src/fp/array/join.spec.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from 'vitest'; +import { join } from './join'; + +describe('join', () => { + it('should join array elements with specified separator', () => { + expect(join([1, 2, 3, 4], ',')).toBe('1,2,3,4'); + expect(join(',')([1, 2, 3, 4])).toBe('1,2,3,4'); + }); + + it('should handle empty arrays', () => { + expect(join([], ',')).toBe(''); + expect(join(',')([])).toBe(''); + }); + + it('should work with different separators', () => { + expect(join([1, 2, 3], '')).toBe('123'); + expect(join('')([1, 2, 3])).toBe('123'); + expect(join([1, 2, 3], ' - ')).toBe('1 - 2 - 3'); + expect(join(' - ')([1, 2, 3])).toBe('1 - 2 - 3'); + }); + + it('should work with different types', () => { + expect(join(['a', 'b', 'c'], '+')).toBe('a+b+c'); + expect(join('+')(['a', 'b', 'c'])).toBe('a+b+c'); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3, 4]; + const arr2 = [1, 2, 3, 4]; + + join(arr, ','); + join(',')(arr2); + + expect(arr).toEqual([1, 2, 3, 4]); + expect(arr2).toEqual([1, 2, 3, 4]); + }); +}); diff --git a/src/fp/array/join.ts b/src/fp/array/join.ts new file mode 100644 index 000000000..2aae55628 --- /dev/null +++ b/src/fp/array/join.ts @@ -0,0 +1,37 @@ +/** + * Joins all elements of an array into a string with specified separator. + * + * @template T - The type of array. + * @param {string} separator - The string used to separate array elements. + * @returns {(arr: T) => string} A function that takes an array and returns a string with all elements joined. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const joinWithComma = join(','); + * const result = joinWithComma(arr); + * // result will be "1,2,3,4,5" + */ +export function join(separator: string): (arr: T) => string; +/** + * Joins all elements of an array into a string with specified separator. + * + * @template T - The type of array. + * @param {T} arr - The array to join. + * @param {string} separator - The string used to separate array elements. + * @returns {string} A string with all array elements joined. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const result = join(arr, ','); + * // result will be "1,2,3,4,5" + */ +export function join(arr: T, separator: string): string; + +export function join(arrOrSeparator: T | string, separator?: string) { + if (separator === undefined && typeof arrOrSeparator === 'string') { + return (arr: T) => join(arr, arrOrSeparator); + } + + const arr = arrOrSeparator as T; + return arr.join(separator); +} From 1b243a13be0787b8346449d3acabfa76dbf1f187 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 14:17:21 +0900 Subject: [PATCH 26/30] feat. add fp/some and fix logics --- src/fp/array/includes.ts | 9 +++++++- src/fp/array/some.spec.ts | 35 +++++++++++++++++++++++++++++ src/fp/array/some.ts | 47 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/fp/array/some.spec.ts create mode 100644 src/fp/array/some.ts diff --git a/src/fp/array/includes.ts b/src/fp/array/includes.ts index 1e904d719..872407211 100644 --- a/src/fp/array/includes.ts +++ b/src/fp/array/includes.ts @@ -33,5 +33,12 @@ export function includes(arrOrSearchElement: T | T[number], } const arr = arrOrSearchElement as T; - return arr.includes(searchElement as T[number]); + + for (const item of arr) { + if (item === searchElement) { + return true; + } + } + + return false; } diff --git a/src/fp/array/some.spec.ts b/src/fp/array/some.spec.ts new file mode 100644 index 000000000..ab3549282 --- /dev/null +++ b/src/fp/array/some.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest'; +import { some } from './some'; + +describe('some', () => { + it('should return true when any element passes the test', () => { + expect(some([1, 2, 3, 4], value => value % 2 === 0)).toBe(true); + expect(some(value => value % 2 === 0)([1, 2, 3, 4])).toBe(true); + }); + + it('should return false when no element passes the test', () => { + expect(some([1, 3, 5, 7], value => value % 2 === 0)).toBe(false); + expect(some(value => value % 2 === 0)([1, 3, 5, 7])).toBe(false); + }); + + it('should handle empty arrays', () => { + expect(some([], () => true)).toBe(false); + expect(some(() => true)([])).toBe(false); + }); + + it('should work with different types', () => { + expect(some(['abc', 'def', 'ghi'], str => str.startsWith('d'))).toBe(true); + expect(some(str => str.startsWith('d'))(['abc', 'def', 'ghi'])).toBe(true); + }); + + it('should not change value of original array', () => { + const arr = [1, 2, 3, 4]; + const arr2 = [1, 2, 3, 4]; + + some(arr, value => value > 2); + some(value => value > 2)(arr2); + + expect(arr).toEqual([1, 2, 3, 4]); + expect(arr2).toEqual([1, 2, 3, 4]); + }); +}); diff --git a/src/fp/array/some.ts b/src/fp/array/some.ts new file mode 100644 index 000000000..6bedc6aec --- /dev/null +++ b/src/fp/array/some.ts @@ -0,0 +1,47 @@ +/** + * Tests whether at least one element in the array passes the test implemented by the provided function. + * + * @template T - The type of array. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {(arr: T) => boolean} A function that takes an array and returns whether any element passes the test. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const hasEven = some(value => value % 2 === 0); + * const result = hasEven(arr); + * // result will be true + */ +export function some(predicate: (value: T[number]) => boolean): (arr: T) => boolean; +/** + * Tests whether at least one element in the array passes the test implemented by the provided function. + * + * @template T - The type of array. + * @param {T} arr - The array to test. + * @param {(value: T[number]) => boolean} predicate - The function to test each element. + * @returns {boolean} Whether any element in the array passes the test. + * + * @example + * const arr = [1, 2, 3, 4, 5]; + * const result = some(arr, value => value % 2 === 0); + * // result will be true + */ +export function some(arr: T, predicate: (value: T[number]) => boolean): boolean; + +export function some( + arrOrPredicate: T | ((value: T[number]) => boolean), + predicate?: (value: T[number]) => boolean +) { + if (predicate == null) { + return (arr: T) => some(arr, arrOrPredicate as (value: T[number]) => boolean); + } + + const arr = arrOrPredicate as T; + + for (const item of arr) { + if (predicate(item)) { + return true; + } + } + + return false; +} From 8a2c4e32d760720119290a78247a23ef60d2988b Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 14:24:22 +0900 Subject: [PATCH 27/30] feat. add sort and sortBy --- src/fp/array/sort.spec.ts | 30 +++++++++++++++++ src/fp/array/sort.ts | 66 +++++++++++++++++++++++++++++++++++++ src/fp/array/sortBy.spec.ts | 49 +++++++++++++++++++++++++++ src/fp/array/sortBy.ts | 44 +++++++++++++++++++++++++ 4 files changed, 189 insertions(+) create mode 100644 src/fp/array/sort.spec.ts create mode 100644 src/fp/array/sort.ts create mode 100644 src/fp/array/sortBy.spec.ts create mode 100644 src/fp/array/sortBy.ts diff --git a/src/fp/array/sort.spec.ts b/src/fp/array/sort.spec.ts new file mode 100644 index 000000000..fcb1a2a52 --- /dev/null +++ b/src/fp/array/sort.spec.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from 'vitest'; +import { sort } from './sort'; + +describe('sort', () => { + it('should sort array in ascending order', () => { + expect(sort([3, 1, 4, 1, 5], (a, b) => a - b)).toEqual([1, 1, 3, 4, 5]); + expect(sort((a, b) => a - b)([3, 1, 4, 1, 5])).toEqual([1, 1, 3, 4, 5]); + }); + + it('should sort array in descending order', () => { + expect(sort([3, 1, 4, 1, 5], (a, b) => b - a)).toEqual([5, 4, 3, 1, 1]); + expect(sort((a, b) => b - a)([3, 1, 4, 1, 5])).toEqual([5, 4, 3, 1, 1]); + }); + + it('should work with different types', () => { + expect(sort(['c', 'a', 'b'], (a, b) => a.localeCompare(b))).toEqual(['a', 'b', 'c']); + expect(sort((a, b) => a.localeCompare(b))(['c', 'a', 'b'])).toEqual(['a', 'b', 'c']); + }); + + it('should not change value of original array', () => { + const arr = [3, 1, 4, 1, 5]; + const arr2 = [3, 1, 4, 1, 5]; + + sort(arr, (a, b) => a - b); + sort((a, b) => a - b)(arr2); + + expect(arr).toEqual([3, 1, 4, 1, 5]); + expect(arr2).toEqual([3, 1, 4, 1, 5]); + }); +}); diff --git a/src/fp/array/sort.ts b/src/fp/array/sort.ts new file mode 100644 index 000000000..7d9544376 --- /dev/null +++ b/src/fp/array/sort.ts @@ -0,0 +1,66 @@ +/** + * Sorts an array in ascending order. + * + * @template T - The type of array. + * @param {(a: T[number], b: T[number]) => number} comparator - The function to compare elements. + * @returns {(arr: T) => T} A function that takes an array and returns a new sorted array. + * + * @example + * const arr = [3, 1, 4, 1, 5]; + * const sortNumbers = sort((a, b) => a - b); + * const result = sortNumbers(arr); + * // result will be [1, 1, 3, 4, 5] + */ +export function sort(comparator: (a: T[number], b: T[number]) => number): (arr: T) => T; +/** + * Sorts an array in ascending order. + * + * @template T - The type of array. + * @param {T} arr - The array to sort. + * @param {(a: T[number], b: T[number]) => number} comparator - The function to compare elements. + * @returns {T} A new sorted array. + * + * @example + * const arr = [3, 1, 4, 1, 5]; + * const result = sort(arr, (a, b) => a - b); + * // result will be [1, 1, 3, 4, 5] + */ +export function sort(arr: T, comparator: (a: T[number], b: T[number]) => number): T; + +export function sort( + arrOrComparator: T | ((a: T[number], b: T[number]) => number), + comparator?: (a: T[number], b: T[number]) => number +) { + if (typeof arrOrComparator === 'function') { + return (arr: T) => sort(arr, arrOrComparator as (a: T[number], b: T[number]) => number); + } + + const arr = [...(arrOrComparator as T)]; + + // Quick sort implementation + const quickSort = (low: number, high: number) => { + if (low < high) { + const pivotIndex = partition(low, high); + quickSort(low, pivotIndex - 1); + quickSort(pivotIndex + 1, high); + } + }; + + const partition = (low: number, high: number) => { + const pivot = arr[high]; + let i = low - 1; + + for (let j = low; j < high; j++) { + if (comparator!(arr[j], pivot) <= 0) { + i++; + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + } + + [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]; + return i + 1; + }; + + quickSort(0, arr.length - 1); + return arr; +} diff --git a/src/fp/array/sortBy.spec.ts b/src/fp/array/sortBy.spec.ts new file mode 100644 index 000000000..52460d091 --- /dev/null +++ b/src/fp/array/sortBy.spec.ts @@ -0,0 +1,49 @@ +import { describe, expect, it } from 'vitest'; +import { sortBy } from './sortBy'; + +describe('sortBy', () => { + it('should sort array by key selector', () => { + const users = [ + { name: 'fred', age: 48 }, + { name: 'barney', age: 36 }, + { name: 'fred', age: 40 }, + ]; + + expect(sortBy(users, user => user.age)).toEqual([ + { name: 'barney', age: 36 }, + { name: 'fred', age: 40 }, + { name: 'fred', age: 48 }, + ]); + + expect(sortBy(user => user.age)(users)).toEqual([ + { name: 'barney', age: 36 }, + { name: 'fred', age: 40 }, + { name: 'fred', age: 48 }, + ]); + }); + + it('should sort array by string key', () => { + const users = [ + { name: 'fred', age: 48 }, + { name: 'barney', age: 36 }, + { name: 'fred', age: 40 }, + ]; + + expect(sortBy(users, user => user.name)).toEqual([ + { name: 'barney', age: 36 }, + { name: 'fred', age: 48 }, + { name: 'fred', age: 40 }, + ]); + }); + + it('should not change value of original array', () => { + const arr = [{ id: 3 }, { id: 1 }, { id: 2 }]; + const arr2 = [{ id: 3 }, { id: 1 }, { id: 2 }]; + + sortBy(arr, item => item.id); + sortBy(item => item.id)(arr2); + + expect(arr).toEqual([{ id: 3 }, { id: 1 }, { id: 2 }]); + expect(arr2).toEqual([{ id: 3 }, { id: 1 }, { id: 2 }]); + }); +}); diff --git a/src/fp/array/sortBy.ts b/src/fp/array/sortBy.ts new file mode 100644 index 000000000..f2d08cd0e --- /dev/null +++ b/src/fp/array/sortBy.ts @@ -0,0 +1,44 @@ +import { sortBy as sortByToolkit } from '../../array/sortBy'; + +/** + * Sorts an array by the results of running each element through a key selector function. + * + * @template T - The type of array. + * @template U - The type of the sort key. + * @param {(value: T[number]) => U} keySelector - The function to select the sort key. + * @returns {(arr: T) => T} A function that takes an array and returns a new sorted array. + * + * @example + * const users = [{ name: 'fred', age: 48 }, { name: 'barney', age: 36 }]; + * const sortByAge = sortBy(user => user.age); + * const result = sortByAge(users); + * // result will be [{ name: 'barney', age: 36 }, { name: 'fred', age: 48 }] + */ +export function sortBy(keySelector: (value: T[number]) => U): (arr: T) => T; +/** + * Sorts an array by the results of running each element through a key selector function. + * + * @template T - The type of array. + * @template U - The type of the sort key. + * @param {T} arr - The array to sort. + * @param {(value: T[number]) => U} keySelector - The function to select the sort key. + * @returns {T} A new sorted array. + * + * @example + * const users = [{ name: 'fred', age: 48 }, { name: 'barney', age: 36 }]; + * const result = sortBy(users, user => user.age); + * // result will be [{ name: 'barney', age: 36 }, { name: 'fred', age: 48 }] + */ +export function sortBy(arr: T, keySelector: (value: T[number]) => U): T; + +export function sortBy( + arrOrKeySelector: T | ((value: T[number]) => U), + keySelector?: (value: T[number]) => U +) { + if (typeof arrOrKeySelector === 'function') { + return (arr: T) => sortBy(arr, arrOrKeySelector as (value: T[number]) => U); + } + + const arr = arrOrKeySelector as T; + return sortByToolkit(arr as any, [keySelector!]) as T; +} From e69e432f4e9a076ad9e667dc5efc7563d55c9701 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 15:37:25 +0900 Subject: [PATCH 28/30] feat. add differenceBy, differenceWith --- src/fp/array/differenceBy.spec.ts | 27 +++++++++++++++ src/fp/array/differenceBy.ts | 54 +++++++++++++++++++++++++++++ src/fp/array/differenceWith.spec.ts | 32 +++++++++++++++++ src/fp/array/differenceWith.ts | 53 ++++++++++++++++++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 src/fp/array/differenceBy.spec.ts create mode 100644 src/fp/array/differenceBy.ts create mode 100644 src/fp/array/differenceWith.spec.ts create mode 100644 src/fp/array/differenceWith.ts diff --git a/src/fp/array/differenceBy.spec.ts b/src/fp/array/differenceBy.spec.ts new file mode 100644 index 000000000..9fc30be3c --- /dev/null +++ b/src/fp/array/differenceBy.spec.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest'; +import { differenceBy } from './differenceBy'; + +describe('differenceBy', () => { + it('should compute the difference using the mapper function', () => { + const arr = [2.1, 1.2, 3.3]; + expect(differenceBy(arr, [2.1, 1.2], Math.floor)).toEqual([3.3]); + expect(differenceBy([2.1, 1.2], Math.floor)(arr)).toEqual([3.3]); + }); + + it('should work with object arrays', () => { + const arr = [{ x: 1 }, { x: 2 }, { x: 3 }]; + expect(differenceBy(arr, [{ x: 1 }, { x: 2 }], obj => obj.x)).toEqual([{ x: 3 }]); + expect(differenceBy([{ x: 1 }, { x: 2 }], obj => obj.x)(arr)).toEqual([{ x: 3 }]); + }); + + it('should not modify the original array', () => { + const arr = [2.1, 1.2, 3.3]; + const arr2 = [2.1, 1.2, 3.3]; + + differenceBy(arr, [2.1], Math.floor); + differenceBy([2.1], Math.floor)(arr2); + + expect(arr).toEqual([2.1, 1.2, 3.3]); + expect(arr2).toEqual([2.1, 1.2, 3.3]); + }); +}); diff --git a/src/fp/array/differenceBy.ts b/src/fp/array/differenceBy.ts new file mode 100644 index 000000000..ff6c494ee --- /dev/null +++ b/src/fp/array/differenceBy.ts @@ -0,0 +1,54 @@ +import { differenceBy as differenceByToolkit } from '../../array/differenceBy'; + +/** + * Computes the difference between two arrays after mapping their elements through a provided function. + * + * @template T - The type of array. + * @template U - The type of the mapped value. + * @param {(value: T[number]) => U} mapper - The function to map the elements. + * @returns {(arr: T) => T} A function that takes an array and returns a new array with the difference. + * + * @example + * const numbers = [2.1, 1.2, 3.3]; + * const diffByFloor = differenceBy(Math.floor); + * const result = diffByFloor([2.1, 1.2]); + * // result will be [3.3] + */ +export function differenceBy( + values: T, + mapper: (value: T[number]) => U +): (arr: T) => T; +/** + * Computes the difference between two arrays after mapping their elements through a provided function. + * + * @template T - The type of array. + * @template U - The type of the mapped value. + * @param {T} arr - The array to inspect. + * @param {T} values - The values to exclude. + * @param {(value: T[number]) => U} mapper - The function to map the elements. + * @returns {T} A new array with the difference. + * + * @example + * const numbers = [2.1, 1.2, 3.3]; + * const result = differenceBy(numbers, [2.1, 1.2], Math.floor); + * // result will be [3.3] + */ +export function differenceBy( + arr: T, + values: T, + mapper: (value: T[number]) => U +): T; + +export function differenceBy( + arrOrValues: T, + valuesOrMapper: T | ((value: T[number]) => U), + mapper?: (value: T[number]) => U +) { + if (mapper === undefined && typeof valuesOrMapper === 'function') { + return (arr: T) => differenceBy(arr, arrOrValues, valuesOrMapper); + } + + const arr = arrOrValues as T; + const values = valuesOrMapper as T; + return differenceByToolkit(arr, values, mapper!) as T; +} diff --git a/src/fp/array/differenceWith.spec.ts b/src/fp/array/differenceWith.spec.ts new file mode 100644 index 000000000..5bcb1f16e --- /dev/null +++ b/src/fp/array/differenceWith.spec.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from 'vitest'; +import { differenceWith } from './differenceWith'; + +describe('differenceWith', () => { + it('should compute the difference using the comparator function', () => { + const arr = [{ x: 1 }, { x: 2 }, { x: 3 }]; + const comparator = (a: { x: number }, b: { x: number }) => a.x === b.x; + + expect(differenceWith(arr, [{ x: 1 }, { x: 2 }], comparator)).toEqual([{ x: 3 }]); + expect(differenceWith([{ x: 1 }, { x: 2 }], comparator)(arr)).toEqual([{ x: 3 }]); + }); + + it('should work with number arrays', () => { + const arr = [1.1, 2.2, 3.3]; + const comparator = (a: number, b: number) => Math.floor(a) === Math.floor(b); + + expect(differenceWith(arr, [1.9, 2.8], comparator)).toEqual([3.3]); + expect(differenceWith([1.9, 2.8], comparator)(arr)).toEqual([3.3]); + }); + + it('should not modify the original array', () => { + const arr = [{ x: 1 }, { x: 2 }, { x: 3 }]; + const arr2 = [{ x: 1 }, { x: 2 }, { x: 3 }]; + const comparator = (a: { x: number }, b: { x: number }) => a.x === b.x; + + differenceWith(arr, [{ x: 1 }], comparator); + differenceWith([{ x: 1 }], comparator)(arr2); + + expect(arr).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }]); + expect(arr2).toEqual([{ x: 1 }, { x: 2 }, { x: 3 }]); + }); +}); diff --git a/src/fp/array/differenceWith.ts b/src/fp/array/differenceWith.ts new file mode 100644 index 000000000..08468334f --- /dev/null +++ b/src/fp/array/differenceWith.ts @@ -0,0 +1,53 @@ +import { differenceWith as differenceWithToolkit } from '../../array/differenceWith'; + +/** + * Computes the difference between two arrays using a custom comparator function. + * + * @template T - The type of array. + * @param {T} values - The values to exclude. + * @param {(x: T[number], y: T[number]) => boolean} comparator - The function to compare elements. + * @returns {(arr: T) => T} A function that takes an array and returns a new array with the difference. + * + * @example + * const objects = [{ x: 1 }, { x: 2 }, { x: 3 }]; + * const diffByX = differenceWith([{ x: 1 }, { x: 2 }], (a, b) => a.x === b.x); + * const result = diffByX(objects); + * // result will be [{ x: 3 }] + */ +export function differenceWith( + values: T, + comparator: (x: T[number], y: T[number]) => boolean +): (arr: T) => T; +/** + * Computes the difference between two arrays using a custom comparator function. + * + * @template T - The type of array. + * @param {T} arr - The array to inspect. + * @param {T} values - The values to exclude. + * @param {(x: T[number], y: T[number]) => boolean} comparator - The function to compare elements. + * @returns {T} A new array with the difference. + * + * @example + * const objects = [{ x: 1 }, { x: 2 }, { x: 3 }]; + * const result = differenceWith(objects, [{ x: 1 }, { x: 2 }], (a, b) => a.x === b.x); + * // result will be [{ x: 3 }] + */ +export function differenceWith( + arr: T, + values: T, + comparator: (x: T[number], y: T[number]) => boolean +): T; + +export function differenceWith( + arrOrValues: T, + valuesOrComparator: T | ((x: T[number], y: T[number]) => boolean), + comparator?: (x: T[number], y: T[number]) => boolean +) { + if (comparator === undefined && typeof valuesOrComparator === 'function') { + return (arr: T) => differenceWith(arr, arrOrValues, valuesOrComparator); + } + + const arr = arrOrValues as T; + const values = valuesOrComparator as T; + return differenceWithToolkit(arr, values, comparator!) as T; +} From 9bed7de62f66c6ff835c229624b2ac55cdba7688 Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 15:49:01 +0900 Subject: [PATCH 29/30] add fp/drop* --- src/fp/array/drop.spec.ts | 46 +++++++++++++++++++++++ src/fp/array/drop.ts | 45 ++++++++++++++++++++++ src/fp/array/dropRight.spec.ts | 46 +++++++++++++++++++++++ src/fp/array/dropRight.ts | 45 ++++++++++++++++++++++ src/fp/array/dropRightWhile.spec.ts | 53 ++++++++++++++++++++++++++ src/fp/array/dropRightWhile.ts | 58 +++++++++++++++++++++++++++++ src/fp/array/dropWhile.spec.ts | 47 +++++++++++++++++++++++ src/fp/array/dropWhile.ts | 58 +++++++++++++++++++++++++++++ 8 files changed, 398 insertions(+) create mode 100644 src/fp/array/drop.spec.ts create mode 100644 src/fp/array/drop.ts create mode 100644 src/fp/array/dropRight.spec.ts create mode 100644 src/fp/array/dropRight.ts create mode 100644 src/fp/array/dropRightWhile.spec.ts create mode 100644 src/fp/array/dropRightWhile.ts create mode 100644 src/fp/array/dropWhile.spec.ts create mode 100644 src/fp/array/dropWhile.ts diff --git a/src/fp/array/drop.spec.ts b/src/fp/array/drop.spec.ts new file mode 100644 index 000000000..f60525c7e --- /dev/null +++ b/src/fp/array/drop.spec.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest'; +import { drop } from './drop'; + +describe('drop', () => { + it( + "(non-curried) should drop `itemsCount` elements from an array from the beginning", + () => { + expect(drop([1.2, 2.3, 3.4], 1)).toEqual([2.3, 3.4]); + expect(drop(['a', 'b', 'c', 'd'], 2)).toEqual(['c', 'd']); + } + ); + + it("(curried) should drop `itemsCount` elements from an array from the beginning", () => { + expect(drop(1)([1.2, 2.3, 3.4])).toEqual([2.3, 3.4]); + expect(drop(2)(['a', 'b', 'c', 'd'])).toEqual(['c', 'd']); + }); + + it("(non-curried) should return all elements if itemsCount < 1", () => { + expect(drop([1.2, 2.3, 3.4], 0)).toEqual([1.2, 2.3, 3.4]); + expect(drop([1.2, 2.3, 3.4], -1)).toEqual([1.2, 2.3, 3.4]); + }); + + it("(curried) should return all elements if itemsCount < 1", () => { + expect(drop(0)([1.2, 2.3, 3.4])).toEqual([1.2, 2.3, 3.4]); + expect(drop(-1)([1.2, 2.3, 3.4])).toEqual([1.2, 2.3, 3.4]); + }); + + it("(non-curried) should coerce itemsCount to an integer", () => { + expect(drop([1.2, 2.3, 3.4], 1.5)).toEqual([2.3, 3.4]); + }); + + it("(curried) should coerce itemsCount to an integer", () => { + expect(drop(1.5)([1.2, 2.3, 3.4])).toEqual([2.3, 3.4]); + }); + + it( + "(non-curried) should return empty array if itemsCount >= arr.length", + () => { + expect(drop([1.2, 2.3, 3.4], 4)).toEqual([]); + } + ); + + it("(curried) should return empty array if itemsCount >= arr.length", () => { + expect(drop(4)([1.2, 2.3, 3.4])).toEqual([]); + }); +}); diff --git a/src/fp/array/drop.ts b/src/fp/array/drop.ts new file mode 100644 index 000000000..915bb33c5 --- /dev/null +++ b/src/fp/array/drop.ts @@ -0,0 +1,45 @@ +import { drop as dropToolkit } from '../../array/drop'; + +/** + * Removes a specified number of elements from the beginning of an array and returns the rest. + * + * This function takes an array and a number, and returns a new array with the specified number + * of elements removed from the start. + * + * @template T - The type of elements in the array. + * @param {T[]} arr - The array from which to drop elements. + * @param {number} itemsCount - The number of elements to drop from the beginning of the array. + * @returns {T[]} A new array with the specified number of elements removed from the start. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = drop(array, 2); + * // result will be [3, 4, 5] since the first two elements are dropped. + */ +export function drop(arr: readonly T[], itemsCount: number): T[]; + +/** + * Removes a specified number of elements from the beginning of an array and returns the rest. + * + * This function takes an array and a number, and returns a new array with the specified number + * of elements removed from the start. + * + * @template T - The type of elements in the array. + * @param {number} itemsCount - The number of elements to drop from the beginning of the array. + * @returns {(arr: T[]) => T[]} A function that receive the array from which to drop elements as argument and returns a new array with the specified number of elements removed from the start. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = drop(2)(array); + * // result will be [3, 4, 5] since the first two elements are dropped. + */ +export function drop(itemsCount: number): (arr: readonly T[]) => T[]; + +export function drop(arrOrItemsCount: readonly T[] | number, itemsCount?: number) { + if (itemsCount == null) { + return (arr: readonly T[]) => drop(arr, arrOrItemsCount as number); + } + + const arr = arrOrItemsCount as readonly T[]; + return dropToolkit(arr, itemsCount); +} diff --git a/src/fp/array/dropRight.spec.ts b/src/fp/array/dropRight.spec.ts new file mode 100644 index 000000000..e2e8b3c96 --- /dev/null +++ b/src/fp/array/dropRight.spec.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from 'vitest'; +import { dropRight } from './dropRight'; + +describe('dropRight', () => { + it( + "(non-curried) should drop `itemsCount` elements from an array from the end", + () => { + expect(dropRight([1.2, 2.3, 3.4], 1)).toEqual([1.2, 2.3]); + expect(dropRight(['a', 'b', 'c', 'd'], 2)).toEqual(['a', 'b']); + } + ); + + it("(curried) should drop `itemsCount` elements from an array from the end", () => { + expect(dropRight(1)([1.2, 2.3, 3.4])).toEqual([1.2, 2.3]); + expect(dropRight(2)(['a', 'b', 'c', 'd'])).toEqual(['a', 'b']); + }); + + it("(non-curried) should return all elements if itemsCount < 1", () => { + expect(dropRight([1.2, 2.3, 3.4], 0)).toEqual([1.2, 2.3, 3.4]); + expect(dropRight([1.2, 2.3, 3.4], -1)).toEqual([1.2, 2.3, 3.4]); + }); + + it("(curried) should return all elements if itemsCount < 1", () => { + expect(dropRight(0)([1.2, 2.3, 3.4])).toEqual([1.2, 2.3, 3.4]); + expect(dropRight(-1)([1.2, 2.3, 3.4])).toEqual([1.2, 2.3, 3.4]); + }); + + it("(non-curried) should coerce itemsCount to an integer", () => { + expect(dropRight([1.2, 2.3, 3.4], 1.5)).toEqual([1.2, 2.3]); + }); + + it("(curried) should coerce itemsCount to an integer", () => { + expect(dropRight(1.5)([1.2, 2.3, 3.4])).toEqual([1.2, 2.3]); + }); + + it( + "(non-curried) should return empty array if itemsCount >= arr.length", + () => { + expect(dropRight([1.2, 2.3, 3.4], 4)).toEqual([]); + } + ); + + it("(curried) should return empty array if itemsCount >= arr.length", () => { + expect(dropRight(4)([1.2, 2.3, 3.4])).toEqual([]); + }); +}); diff --git a/src/fp/array/dropRight.ts b/src/fp/array/dropRight.ts new file mode 100644 index 000000000..736bbd8be --- /dev/null +++ b/src/fp/array/dropRight.ts @@ -0,0 +1,45 @@ +import { dropRight as dropRightToolkit } from '../../array/dropRight'; + +/** + * Removes a specified number of elements from the end of an array and returns the rest. + * + * This function takes an array and a number, and returns a new array with the specified number + * of elements removed from the end. + * + * @template T - The type of elements in the array. + * @param {T[]} arr - The array from which to drop elements. + * @param {number} itemsCount - The number of elements to drop from the end of the array. + * @returns {T[]} A new array with the specified number of elements removed from the end. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = dropRight(array, 2); + * // result will be [1, 2, 3] since the last two elements are dropped. + */ +export function dropRight(arr: readonly T[], itemsCount: number): T[]; + +/** + * Removes a specified number of elements from the end of an array and returns the rest. + * + * This function takes an array and a number, and returns a new array with the specified number + * of elements removed from the end. + * + * @template T - The type of elements in the array. + * @param {number} itemsCount - The number of elements to drop from the end of the array. + * @returns {(arr: T[]) => T[]} A function that receive the array from which to drop elements as argument and returns a new array with the specified number of elements removed from the end. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = dropRight(2)(array); + * // result will be [1, 2, 3] since the last two elements are dropped. + */ +export function dropRight(itemsCount: number): (arr: readonly T[]) => T[]; + +export function dropRight(arrOrItemsCount: readonly T[] | number, itemsCount?: number) { + if (itemsCount == null) { + return (arr: readonly T[]) => dropRight(arr, arrOrItemsCount as number); + } + + const arr = arrOrItemsCount as readonly T[]; + return dropRightToolkit(arr, itemsCount); +} diff --git a/src/fp/array/dropRightWhile.spec.ts b/src/fp/array/dropRightWhile.spec.ts new file mode 100644 index 000000000..db3e4e971 --- /dev/null +++ b/src/fp/array/dropRightWhile.spec.ts @@ -0,0 +1,53 @@ +import { describe, expect, it } from 'vitest'; +import { dropRightWhile } from './dropRightWhile'; + +describe('dropRightWhile', () => { + it( + "(non-curried) should drop elements from an array until `canContinueDropping` returns false, from the end", + () => { + expect(dropRightWhile([1.2, 2.3, 3.4], x => x < 2)).toEqual([1.2, 2.3, 3.4]); + + const items = [ + { id: 1, enabled: false }, + { id: 2, enabled: true }, + { id: 3, enabled: false }, + ]; + + expect(dropRightWhile(items, x => !x.enabled)).toEqual([ + { + id: 1, + enabled: false, + }, + { + id: 2, + enabled: true, + }, + ]); + + expect(dropRightWhile([1, 2, 3], x => x < 4)).toEqual([]); + } + ); + + it("(curried) should drop elements from an array until `canContinueDropping` returns false, from the end", () => { + expect(dropRightWhile(x => x < 2)([1.2, 2.3, 3.4])).toEqual([1.2, 2.3, 3.4]); + + const items = [ + { id: 1, enabled: false }, + { id: 2, enabled: true }, + { id: 3, enabled: false }, + ]; + + expect(dropRightWhile(x => !x.enabled)(items)).toEqual([ + { + id: 1, + enabled: false, + }, + { + id: 2, + enabled: true, + }, + ]); + + expect(dropRightWhile(x => x < 4)([1, 2, 3])).toEqual([]); + }); +}); diff --git a/src/fp/array/dropRightWhile.ts b/src/fp/array/dropRightWhile.ts new file mode 100644 index 000000000..0101066e8 --- /dev/null +++ b/src/fp/array/dropRightWhile.ts @@ -0,0 +1,58 @@ +import { dropRightWhile as dropRightWhileToolkit } from '../../array/dropRightWhile'; + +/** + * Removes elements from the end of an array until the predicate returns false. + * + * This function iterates over an array from the end and drops elements until the provided + * predicate function returns false. It then returns a new array with the remaining elements. + * + * @template T - The type of elements in the array. + * @param {T[]} arr - The array from which to drop elements. + * @param {(item: T, index: number, arr: T[]) => boolean} canContinueDropping - A predicate function that determines + * whether to continue dropping elements. The function is called with each element from the end, + * and dropping continues as long as it returns true. + * @returns {T[]} A new array with the elements remaining after the predicate returns false. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = dropRightWhile(array, x => x > 3); + * // result will be [1, 2, 3] since elements greater than 3 are dropped from the end. + */ +export function dropRightWhile( + arr: readonly T[], + canContinueDropping: (item: T, index: number, arr: readonly T[]) => boolean +): T[]; + +/** + * Removes elements from the end of an array until the predicate returns false. + * + * This function iterates over an array from the end and drops elements until the provided + * predicate function returns false. It then returns a new array with the remaining elements. + * + * @template T - The type of elements in the array. + * @param {(item: T, index: number, arr: T[]) => boolean} canContinueDropping - A predicate function that determines + * whether to continue dropping elements. The function is called with each element from the end, + * and dropping continues as long as it returns true. + * @returns {(arr: T[]) => T[]} A function that receive the array from which to drop elements as argument and returns a new array with the elements remaining after the predicate returns false. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = dropRightWhile(x => x > 3)(array); + * // result will be [1, 2, 3] since elements greater than 3 are dropped from the end. + */ +export function dropRightWhile( + canContinueDropping: (item: T, index: number, arr: readonly T[]) => boolean +): (arr: readonly T[]) => T[]; + +export function dropRightWhile( + arrOrCanContinueDropping: readonly T[] | ((item: T, index: number, arr: readonly T[]) => boolean), + canContinueDropping?: (item: T, index: number, arr: readonly T[]) => boolean +) { + if (canContinueDropping == null) { + return (arr: readonly T[]) => + dropRightWhile(arr, arrOrCanContinueDropping as (item: T, index: number, arr: readonly T[]) => boolean); + } + + const arr = arrOrCanContinueDropping as readonly T[]; + return dropRightWhileToolkit(arr, canContinueDropping); +} diff --git a/src/fp/array/dropWhile.spec.ts b/src/fp/array/dropWhile.spec.ts new file mode 100644 index 000000000..5cad657c3 --- /dev/null +++ b/src/fp/array/dropWhile.spec.ts @@ -0,0 +1,47 @@ +import { describe, expect, it } from 'vitest'; +import { dropWhile } from './dropWhile'; + +describe('dropWhile', () => { + it( + "(non-curried) should drop elements from an array until `canContinueDropping` returns false, from the beginning", + () => { + expect(dropWhile([1.2, 2.3, 3.4], x => x < 2)).toEqual([2.3, 3.4]); + + const items = [ + { id: 1, enabled: false }, + { id: 2, enabled: true }, + { id: 3, enabled: false }, + ]; + + expect(dropWhile(items, x => !x.enabled)).toEqual([ + { + id: 2, + enabled: true, + }, + { id: 3, enabled: false }, + ]); + + expect(dropWhile([1, 2, 3], x => x < 4)).toEqual([]); + } + ); + + it("(curried) should drop elements from an array until `canContinueDropping` returns false, from the beginning", () => { + expect(dropWhile(x => x < 2)([1.2, 2.3, 3.4])).toEqual([2.3, 3.4]); + + const items = [ + { id: 1, enabled: false }, + { id: 2, enabled: true }, + { id: 3, enabled: false }, + ]; + + expect(dropWhile(x => !x.enabled)(items)).toEqual([ + { + id: 2, + enabled: true, + }, + { id: 3, enabled: false }, + ]); + + expect(dropWhile(x => x < 4)([1, 2, 3])).toEqual([]); + }); +}); diff --git a/src/fp/array/dropWhile.ts b/src/fp/array/dropWhile.ts new file mode 100644 index 000000000..b91f283ac --- /dev/null +++ b/src/fp/array/dropWhile.ts @@ -0,0 +1,58 @@ +import { dropWhile as dropWhileToolkit } from '../../array/dropWhile'; + +/** + * Removes elements from the beginning of an array until the predicate returns false. + * + * This function iterates over an array and drops elements from the start until the provided + * predicate function returns false. It then returns a new array with the remaining elements. + * + * @template T - The type of elements in the array. + * @param {T[]} arr - The array from which to drop elements. + * @param {(item: T, index: number, arr: T[]) => boolean} canContinueDropping - A predicate function that determines + * whether to continue dropping elements. The function is called with each element, and dropping + * continues as long as it returns true. + * @returns {T[]} A new array with the elements remaining after the predicate returns false. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = dropWhile(array, x => x < 3); + * // result will be [3, 4, 5] since elements less than 3 are dropped. + */ +export function dropWhile( + arr: readonly T[], + canContinueDropping: (item: T, index: number, arr: readonly T[]) => boolean +): T[]; + +/** + * Removes elements from the beginning of an array until the predicate returns false. + * + * This function iterates over an array and drops elements from the start until the provided + * predicate function returns false. It then returns a new array with the remaining elements. + * + * @template T - The type of elements in the array. + * @param {(item: T, index: number, arr: T[]) => boolean} canContinueDropping - A predicate function that determines + * whether to continue dropping elements. The function is called with each element, and dropping + * continues as long as it returns true. + * @returns {(arr: T[]) => T[]} A function that receive the array from which to drop elements as argument and returns a new array with the elements remaining after the predicate returns false. + * + * @example + * const array = [1, 2, 3, 4, 5]; + * const result = dropWhile(x => x < 3)(array); + * // result will be [3, 4, 5] since elements less than 3 are dropped. + */ +export function dropWhile( + canContinueDropping: (item: T, index: number, arr: readonly T[]) => boolean +): (arr: readonly T[]) => T[]; + +export function dropWhile( + arrOrCanContinueDropping: readonly T[] | ((item: T, index: number, arr: readonly T[]) => boolean), + canContinueDropping?: (item: T, index: number, arr: readonly T[]) => boolean +) { + if (canContinueDropping == null) { + return (arr: readonly T[]) => + dropWhile(arr, arrOrCanContinueDropping as (item: T, index: number, arr: readonly T[]) => boolean); + } + + const arr = arrOrCanContinueDropping as readonly T[]; + return dropWhileToolkit(arr, canContinueDropping); +} From 02884804e1680df13c125df6fec5931eb677787d Mon Sep 17 00:00:00 2001 From: seungro Date: Fri, 17 Jan 2025 16:05:55 +0900 Subject: [PATCH 30/30] feat. add fp/fill --- src/fp/array/fill.spec.ts | 64 +++++++++++++++++++++++++++++++++++++++ src/fp/array/fill.ts | 48 +++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 src/fp/array/fill.spec.ts create mode 100644 src/fp/array/fill.ts diff --git a/src/fp/array/fill.spec.ts b/src/fp/array/fill.spec.ts new file mode 100644 index 000000000..acbe232ca --- /dev/null +++ b/src/fp/array/fill.spec.ts @@ -0,0 +1,64 @@ +import { describe, expect, it } from 'vitest'; +import { fill } from './fill'; + +describe('fill', () => { + it('(non-curried) should fill the entire array with the specified value', () => { + expect(fill([1, 2, 3], 'a')).toEqual(['a', 'a', 'a']); + expect(fill(Array(3), 2)).toEqual([2, 2, 2]); + }); + + it('(curried) should fill the entire array with the specified value', () => { + expect(fill('a')([1, 2, 3])).toEqual(['a', 'a', 'a']); + expect(fill(2)(Array(3))).toEqual([2, 2, 2]); + }); + + it('(non-curried) should fill part of an array from start to end index', () => { + expect(fill([4, 6, 8, 10], '*', 1, 3)).toEqual([4, '*', '*', 10]); + expect(fill([1, 2, 3, 4, 5], '*', 1, 4)).toEqual([1, '*', '*', '*', 5]); + }); + + it('(curried) should fill part of an array from start to end index', () => { + expect(fill('*', 1, 3)([4, 6, 8, 10])).toEqual([4, '*', '*', 10]); + expect(fill('*', 1, 4)([1, 2, 3, 4, 5])).toEqual([1, '*', '*', '*', 5]); + }); + + it('(non-curried) should fill from specified start position', () => { + expect(fill([1, 2, 3, 4, 5], '*', 2)).toEqual([1, 2, '*', '*', '*']); + }); + + it('(curried) should fill from specified start position', () => { + expect(fill('*', 2)([1, 2, 3, 4, 5])).toEqual([1, 2, '*', '*', '*']); + }); + + it('(non-curried) should fill with negative start position', () => { + expect(fill([1, 2, 3, 4, 5], '*', -3)).toEqual([1, 2, '*', '*', '*']); + }); + + it('(curried) should fill with negative start position', () => { + expect(fill('*', -3)([1, 2, 3, 4, 5])).toEqual([1, 2, '*', '*', '*']); + }); + + it('(non-curried) should fill with positive start and negative end positions', () => { + expect(fill([1, 2, 3, 4, 5], '*', 1, -1)).toEqual([1, '*', '*', '*', 5]); + }); + + it('(curried) should fill with positive start and negative end positions', () => { + expect(fill('*', 1, -1)([1, 2, 3, 4, 5])).toEqual([1, '*', '*', '*', 5]); + }); + + it('(non-curried) should fill with both negative start and end positions', () => { + expect(fill([1, 2, 3, 4, 5], '*', -4, -1)).toEqual([1, '*', '*', '*', 5]); + }); + + it('(curried) should fill with both negative start and end positions', () => { + expect(fill('*', -4, -1)([1, 2, 3, 4, 5])).toEqual([1, '*', '*', '*', 5]); + }); + + it('(non-curried) should not fill if start is greater than end', () => { + expect(fill([1, 2, 3, 4, 5], '*', 3, 2)).toEqual([1, 2, 3, 4, 5]); + }); + + it('(curried) should not fill if start is greater than end', () => { + expect(fill('*', 3, 2)([1, 2, 3, 4, 5])).toEqual([1, 2, 3, 4, 5]); + }); +}); diff --git a/src/fp/array/fill.ts b/src/fp/array/fill.ts new file mode 100644 index 000000000..22ab18061 --- /dev/null +++ b/src/fp/array/fill.ts @@ -0,0 +1,48 @@ +import { fill as fillToolkit } from '../../array/fill'; + +/** + * Creates a function that fills elements of array with value from start up to end. + * + * @template T - The type of array elements. + * @param {T} value - The value to fill array with. + * @param {number} [start=0] - The start position. + * @param {number} [end=array.length] - The end position. + * @returns {(arr: T[]) => T[]} A function that takes an array and returns a new filled array. + * + * @example + * const fillWithA = fill('a', 1, 3); + * const result = fillWithA(['x', 'x', 'x', 'x']); + * // result will be ['x', 'a', 'a', 'x'] + */ +export function fill(value: U, start?: number, end?: number): (arr: T[]) => Array; +/** + * Fills elements of array with value from start up to end. + * + * @template T - The type of array elements. + * @param {T[]} arr - The array to fill. + * @param {T} value - The value to fill array with. + * @param {number} [start=0] - The start position. + * @param {number} [end=array.length] - The end position. + * @returns {T[]} A new array with filled elements. + * + * @example + * const array = ['x', 'x', 'x', 'x']; + * const result = fill(array, 'a', 1, 3); + * // result will be ['x', 'a', 'a', 'x'] + */ +export function fill(arr: T[], value: U, start?: number, end?: number): Array; + +export function fill( + arrOrValue: T[] | T, + valueOrStart?: U | number, + startOrEnd?: number, + end?: number +) { + if (!Array.isArray(arrOrValue)) { + return (arr: T[]) => fill(arr, arrOrValue, valueOrStart as number, startOrEnd); + } + + const arr = arrOrValue; + const value = valueOrStart as T; + return fillToolkit(arr, value, startOrEnd ?? 0, end ?? arr.length); +}