Show HN: FP-pack – Functional pipelines in TypeScript without monads
14 points| superlucky84 | 1 month ago |github.com
I built fp-pack, a small TypeScript functional utility library focused on pipe-first composition.
The goal is to keep pipelines simple and readable, while still supporting early exits and side effects — without introducing monads like Option or Either.
Most code uses plain pipe/pipeAsync. For the few cases that need early termination, fp-pack provides a SideEffect-based pipeline that short-circuits safely.
I also wrote an “AI agent skills” document to help LLMs generate consistent fp-pack-style code.
Feedback, criticism, or questions are very welcome.
epgui|1 month ago
superlucky84|1 month ago
The main difference is that SideEffect isn’t a compositional context — there’s no bind/flatMap, and composition intentionally stops once it appears. It’s meant as an explicit early-exit signal in pipe-first code, not a general computation container.
superlucky84|1 month ago
It’s intentionally not a monad, and I’m curious how others feel about this trade-off compared to Option/Either in real-world TypeScript codebases.
cobbal|1 month ago
eterps|1 month ago
https://github.com/superlucky84/fp-pack?tab=readme-ov-file#s...
Still, this approach is very useful for most business logic, too bad most programming languages don't provide a nice syntax for this.
superlucky84|1 month ago
The SideEffect pattern is intentionally explicit, so without fp-pack context it can look unfamiliar at first. The trade-off is making early exits visible in the code, rather than hiding them in conditionals or exceptions.
In practice, most code stays in plain pipe/pipeAsync. SideEffect is meant for a small number of boundary cases only.
And I agree — better language-level syntax for this kind of pattern would make it much easier to adopt.
wk_end|1 month ago
superlucky84|1 month ago
This happens because `runPipeResult` defaults its generic parameter to `R = any`. When type safety matters, the intended solution is to use `pipeSideEffectStrict`, which preserves all possible SideEffect result types as a precise union throughout the pipeline.
The default version prioritizes ergonomics and simplicity, while the strict version prioritizes type safety.
Also, fp-pack is still in an early stage, so the usability and API choices haven’t been fully validated yet. That’s why feedback like this is especially helpful in shaping the direction of the library.
almosthere|1 month ago
superlucky84|1 month ago
There’s often a gap between what feels conceptually clean and what teams are actually willing to carry cognitively. Rx in particular tends to exceed that budget pretty quickly.
That’s why fp-pack is intentionally narrow — it’s closer to making a few control-flow cases explicit in pipe-first code than introducing a broad new abstraction.
mrkeen|1 month ago
Please tell me you didn't just add SideEffects to a language full of side-effects.
superlucky84|1 month ago
The intent isn’t to add more side effects to an already side-effectful language. It’s closer to the opposite: trying not to handle side effects all over the place, but to surface them as part of a single, explicit flow.
This is less about adding something like Option to a language without nulls, and more about making control-flow boundaries visible in a multi-paradigm language where effects already exist.
It’s not an attempt to pretend the language is pure, just a small step toward more declarative discipline.