Gathering detailed insights and metrics for ts-functional-pipe
Gathering detailed insights and metrics for ts-functional-pipe
Gathering detailed insights and metrics for ts-functional-pipe
Gathering detailed insights and metrics for ts-functional-pipe
Heavily overloaded functions (pipe/compose) for type-safe function composition in TypeScript
npm install ts-functional-pipe
Typescript
Module System
Min. Node Version
Node Version
NPM Version
77.9
Supply Chain
99.5
Quality
75.9
Maintenance
100
Vulnerability
100
License
TypeScript (99.47%)
Dockerfile (0.29%)
JavaScript (0.23%)
Shell (0.02%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
27 Stars
57 Commits
3 Forks
1 Watchers
12 Branches
2 Contributors
Updated on Mar 12, 2025
Latest Version
3.1.2
Package Id
ts-functional-pipe@3.1.2
Unpacked Size
755.80 kB
Size
40.20 kB
File Count
16
NPM Version
8.5.5
Node Version
16.14.0
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
36
In the absence of |>
(the pipe operator) it's useful to have a type-safe pipe function that can compose an a large (up to 64) number of unary functions. This minimal library contains a few different helper functions for this purpose.
NOTE
Versions <=2.x erroneously used the term
compose
for left-to-right function composition. v3 is a major overhaul of this library and contains several breaking changes, both in the code, and in the meaning ofcompose
.These are version >=3 documents. Please find v2.x documentation here
This library makes use of leading/middle rest elements, introduced in Typescript version 4.2
Suppose we have the following unary functions:
1const dinosaurify = (name:string) => `${name}-o-saurus` 2const sayHello = (name:string) => `Hello, ${name}!`
We can compose these functions into a single function using the compose function:
1const sayHelloToDinosaur = compose(sayHello, dinosaurify)
and call it
1sayHelloToDinosaur("mike") // "Hello, mike-o-saurus!"
Note that with compose
, function composition occurs from right-to-left.
The pipe
function composes its parameters from left-to-right, so the equivalent pipe
version of the code above would be:
1const sayHelloToDinosaur_withPipe = pipe(dinosaurify, sayHello)
applyArgs
helperAlternatively, we could have called the applyArgs
helper, which is useful for ensuring that type inference flows inutitively through the composed functions. This makes more sense later when we start using it with (apparently) untyped arrow functions.
1applyArgs("mike").to(pipe(dinosaurify, sayHello)) // "Hello, mike-o-saurus!"
or, less verbosely:
1applyArgs("mike")(pipe(dinosaurify, sayHello)) // "Hello, mike-o-saurus!"
pipeInto
functionThis is shorthand to combine the applyArgs
helper with pipe
, reducing the amount of boilerplate. Using pipeInto
we can rewrite the above as:
1pipeInto("mike", dinosaurify, sayHello)
Pipes work with unary-functions, using the return value of one function as the only parameter to the next function.
Say we create our own versions the Array map and filter functions to work over Iterable<T>
1// helper function for making iterables from generator functions 2const toIterable = <T, TF extends () => IterableIterator<T>>(f: TF) => ({ 3 [Symbol.iterator]: f 4}) 5 6const _map = <T, TOut>(src: Iterable<T>, selector: (v: T, i: number) => TOut): Iterable<TOut> => 7 toIterable(function*() { 8 let c = 0 9 for (const v of src) { 10 yield selector(v, c++) 11 } 12 }) 13 14const _filter = <T>(src: Iterable<T>, pred: (v: T, i: number) => boolean): Iterable<T> => 15 toIterable(function*() { 16 let i = 0 17 for (const x of src) { 18 if (pred(x, i++)) { 19 yield x 20 } 21 } 22 })
Here, the _map
and _filter
are not unary functions so cannot be used in a pipe/compose.
deferP0
We can use the provided deferP0
method to transform these functions into functions that return a unary function (that takes a single parameter that was the first parameter of the original source function)
So it turns functions of the form
(src: TSrc, b: B, c: C, d: D) => R
into functions of the form
(b: B, c: C, d: D) => (src: TSrc) => R
So, to make a composable map
function:
1const map = deferP0(_map)
Here, we transform the _map
function with type
<T, TOut>(src: Iterable<T>, selector: (v: T, i: number) => TOut): Iterable<TOut>
into the generated map
function which has the type
<T, TOut>(selector: (v: T, i: number) => TOut) => (src: Iterable<T>): Iterable<TOut>
As can be seen, we end up with a function that generates a unary function.
We can do the same with _filter
1const filter = deferP0(_filter)
Now the map
and filter
functions that we generated above return unary functions and can be used in a pipe/compose with type inference "flowing" through the composed functions.
map
and filter
with pipe
Let's use them with the pipe
and the applyArgs
helper (so that type information propagates through all the function parameters)
1const transformed = 2 applyArgs([1, 2, 3]).to( 3 pipe( 4 filter(x => x % 2 === 1), // x is inferred as number 5 map(x => x * 2) // x is inferred as number 6 ) 7 ) // iterable with values [2, 6]
When using "untyped" arrow functions, as above, by using the applyArgs
helper, we can see how types are propagated through the functions without needing to provide types for any function parameters. However, we might just want a re-useable function composed of multiple functions, so we can use compose(...unaryFuncs)
or pipe(...unaryFuncs)
on their own... but we'll need to supply type-information, usually in just one place, so that typescript can infer other types successfully:
1const oddNumbersMultipliedByTwo = 2 // pipe is inferred as (src:Iterable<number>)=>Iterable<string> 3 pipe( 4 // typescript can infer all other types when 5 // we provide this input type annotation (number) 6 filter(x:number => x % 2 === 1), 7 map(x => x.toString()), // x is inferred as number 8 map(x => x + " " + x) // x is inferred as string 9 )
So oddNumbersMultipliedByTwoPipe
has the inferred type
(src: Iterable<number>) => Iterable<string>
and when we use it...
1const r = oddMultipliedByTwo([1, 2, 3]) 2// arr has type string[] 3const arr = [...r] // ["1 1", "2 2"]
arr
has type string[]
Created using the wonderful https://github.com/alexjoverm/typescript-library-starter.
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
detected GitHub workflow tokens with excessive permissions
Details
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
no SAST tool detected
Details
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Reason
27 existing vulnerabilities detected
Details
Score
Last Scanned on 2025-05-05
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More