Skip to content

feat(fp): add flow, a reusable composition built on pipe - #1812

Merged
raon0211 merged 1 commit into
mainfrom
work/zen-nightingale-dcf541
Jun 27, 2026
Merged

raon0211 merged 1 commit into
mainfrom
work/zen-nightingale-dcf541

Conversation

@raon0211

@raon0211 raon0211 commented Jun 27, 2026 •

Copy link
Copy Markdown
Collaborator

Overview

Adds flow to es-toolkit/fp — the deferred sibling of pipe. Where pipe(value, ...fns) threads a concrete value through the functions immediately, flow(...fns) returns a reusable function you can call later with different data.

The first function may take any number of arguments; every later function is unary and receives the previous result (same shape as the main es-toolkit flow).

Implementation note: built on pipe

flow does not reimplement composition — it delegates to pipe so lazy-capable operators (map, filter, take, …) are fused and short-circuit exactly as they do in pipe:

  • Single argument (fn(x)): runs pipe(x, ...functions), so a leading lazy operator stays inside the fused run instead of being applied eagerly.
  • Multiple arguments (fn(x, y, …)): only the first function may be variadic, so it is invoked directly (first(...args)) and the rest go through pipe.

Overloads cover up to 15 functions, matching pipe.

Changes

  • src/fp/flow.ts — implementation + JSDoc, 15 overloads, runtime delegates to pipe.
  • src/fp/index.ts, src/fp/index.spec.ts — public export + export test.
  • src/fp/flow.spec.ts — runtime tests (variadic first fn, unary chain, pipe-parity, lazy short-circuit via spy, reusability) + expectTypeOf checks for first-fn params / final return type.
  • Docs in all 4 languages (docs/{,, ko/, ja/, zh_hans/}fp/reference/flow.md), centered on the pipe vs flow difference (immediate vs reusable). Sidebar is auto-discovered, no config change needed.

Benchmarks

  • benchmarks/performance/fp/flow.bench.ts — es-toolkit/fp vs lodash/fp across scalar composition, flow/map, and a flow/map + filter + take lazy short-circuit case.
  • benchmarks/bundle-size/fp/flow.spec.ts — es-toolkit/fp (969 B) vs lodash/fp/flow.

Note: in flow/map (a single eager map over 10k elements, no short-circuit) es-toolkit/fp is slower than lodash/fp — the lazy machinery has fixed overhead that only pays off once an operator can terminate the walk early. The numbers are reported as-is.

Verification

yarn vitest run src/fp/flow.spec.ts src/fp/index.spec.ts   # 12 passed
yarn typecheck                                             # clean
yarn lint                                                  # 0 errors
yarn vitest bench benchmarks/performance/fp/flow.bench.ts --run
yarn vitest run benchmarks/bundle-size/fp/flow.spec.ts     # passed

@vercel

vercel Bot commented Jun 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
es-toolkit Ready Ready Preview, Comment Jun 27, 2026 6:34am

Request Review

@raon0211
raon0211 force-pushed the work/zen-nightingale-dcf541 branch from 2c83077 to 48dc4f5 Compare June 27, 2026 06:29
@raon0211
raon0211 marked this pull request as ready for review June 27, 2026 07:17
@raon0211
raon0211 requested a review from dayongkr as a code owner June 27, 2026 07:17
@raon0211
raon0211 merged commit 1da529f into main Jun 27, 2026
10 checks passed
gwennlbh pushed a commit to cigaleapp/cigale that referenced this pull request Aug 3, 2026
##### [v1.50.0](https://github.com/toss/es-toolkit/blob/HEAD/CHANGELOG.md#Version-v1500)

Released on July 24th, 2026.

- Added the `es-toolkit/types` entrypoint: a declaration-only module of compile-time
  type utilities TypeScript lacks natively — `ValueOf`, `Simplify`, `Writable`,
  `NonEmptyArray`, `DeepPartial`, and `DeepReadonly`. (\[[#1818](toss/es-toolkit#1818)])
- Added `flow` to `es-toolkit/fp`, a reusable data-last composition built on `pipe`. (\[[#1812](toss/es-toolkit#1812)])

The following bring `es-toolkit/compat` closer to Lodash. Behavior for the affected
edge cases now matches Lodash, so results may differ if you relied on the previous output.

- Fixed `compat/intersectionBy` to dedupe a single array (including by the iteratee)
  and to keep results consistent with Lodash. (\[[#1935](toss/es-toolkit#1935)])

- Fixed `compat/findIndex` and `compat/findLastIndex` to coerce a `NaN` `fromIndex`
  to `0` and to convert `fromIndex` to an integer. (\[[#1828](toss/es-toolkit#1828)], \[[#1834](toss/es-toolkit#1834)], \[[#1938](toss/es-toolkit#1938)])

- Fixed `compat/lastIndexOf` to coerce `fromIndex` like Lodash. (\[[#1832](toss/es-toolkit#1832)])

- Fixed `compat/every` to treat a falsy, non-nullish `doesMatch` as a `_.property`
  shorthand instead of identity. (\[[#1940](toss/es-toolkit#1940)])

- Fixed `compat/nth` to support string inputs. (\[[#1833](toss/es-toolkit#1833)])

- Fixed `compat/inRange` to not throw on a lone negative bound. (\[[#1835](toss/es-toolkit#1835)])

- Fixed `compat/toArray` to convert `Set`s to arrays like Lodash. (\[[#1840](toss/es-toolkit#1840)])

- Fixed `compat/values` to treat sparse array holes as `undefined`. (\[[#1894](toss/es-toolkit#1894)])

- Fixed `compat/maxBy` and `compat/minBy` to restore Lodash-compatible comparison. (\[[#1893](toss/es-toolkit#1893)])

- Fixed `compat/includes` to exclude the `length` property when matching array-like values. (\[[#1886](toss/es-toolkit#1886)])

- Fixed the case functions to split ordinal numbers like Lodash, and to count string
  size and padding by code points for multi-byte characters. (\[[#1836](toss/es-toolkit#1836)], \[[#1852](toss/es-toolkit#1852)], \[[#1853](toss/es-toolkit#1853)])

- Fixed `compat/unset` to not treat an own literal dotted key as a deep path. (\[[#1808](toss/es-toolkit#1808)])

- Moved `compat/flattenDepth`'s flattening logic out of `flatten`. (\[[#1847](toss/es-toolkit#1847)])

- Restored the standalone `eq` and `templateSettings` entry points. (\[[#1895](toss/es-toolkit#1895)])

- Fixed `deburr` to remove all combining diacritical marks, matching Lodash. (\[[#1807](toss/es-toolkit#1807)])

- Fixed `partition` to accept any predicate return value, like `Array.prototype.filter`. (\[[#1937](toss/es-toolkit#1937)])

- Fixed `has` and `hasIn` to prioritize nullish literal keys over paths. (\[[#1810](toss/es-toolkit#1810)])

- Fixed `invokeMap` to normalize a string path via `toPath` for `this` binding. (\[[#1814](toss/es-toolkit#1814)])

- Fixed `isDeepKey` to detect deep keys with stricter patterns. (\[[#1621](toss/es-toolkit#1621)])

- Fixed `unzipWith` to return an empty array instead of throwing on empty input. (\[[#1816](toss/es-toolkit#1816)])

- Improved documentation, JSDoc accuracy, and internal refactoring across `compat`
  and `fp`. (\[[#1817](toss/es-toolkit#1817)], \[[#1820](toss/es-toolkit#1820)], \[[#1822](toss/es-toolkit#1822)], \[[#1823](toss/es-toolkit#1823)], \[[#1825](toss/es-toolkit#1825)], \[[#1829](toss/es-toolkit#1829)], \[[#1830](toss/es-toolkit#1830)], \[[#1842](toss/es-toolkit#1842)],
  \[[#1845](toss/es-toolkit#1845)], \[[#1851](toss/es-toolkit#1851)], \[[#1858](toss/es-toolkit#1858)], \[[#1867](toss/es-toolkit#1867)], \[[#1879](toss/es-toolkit#1879)])

We sincerely thank [@Antoliny0919](https://github.com/Antoliny0919), [@raon0211](https://github.com/raon0211), [@dayongkr](https://github.com/dayongkr), [@spokodev](https://github.com/spokodev), [@sarathfrancis90](https://github.com/sarathfrancis90),
[@mayur-shenoy](https://github.com/mayur-shenoy), [@mahirhir](https://github.com/mahirhir), [@kojesung](https://github.com/kojesung), [@Hprogram](https://github.com/Hprogram), [@BangDori](https://github.com/BangDori), and everyone else who
contributed. We appreciate your great efforts!

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview — 48dc4f5a Deployed Jun 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant