Add compose function and extend pipe with overloading
The best way to get type saftey with composition functions is via overloading. This does impose a hard limit on the humber of functions that can be composed. In this case, the limit is 10.
This commit is contained in:
parent
e696e5d9d2
commit
300a538314
@ -1,11 +1,171 @@
|
|||||||
import { type Either, left, right } from './either'
|
import { type Either, left, right } from './either'
|
||||||
import { none, type Option, some } from './option'
|
import { none, type Option, some } from './option'
|
||||||
|
|
||||||
// Pipe function for composition
|
interface Pipe {
|
||||||
export const pipe = <A, B, C>(a: A, ab: (a: A) => B, bc: (b: B) => C): C =>
|
<A>(value: A): A
|
||||||
bc(ab(a))
|
<A, B>(value: A, fn1: (a: A) => B): B
|
||||||
|
<A, B, C>(value: A, fn1: (a: A) => B, fn2: (b: B) => C): C
|
||||||
|
<A, B, C, D>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
): D
|
||||||
|
<A, B, C, D, E>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
): E
|
||||||
|
<A, B, C, D, E, F>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
): F
|
||||||
|
<A, B, C, D, E, F, G>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
): G
|
||||||
|
<A, B, C, D, E, F, G, H>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
): H
|
||||||
|
<A, B, C, D, E, F, G, H, I>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
fn8: (h: H) => I,
|
||||||
|
): I
|
||||||
|
<A, B, C, D, E, F, G, H, I, J>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
fn8: (h: H) => I,
|
||||||
|
fn9: (i: I) => J,
|
||||||
|
): J
|
||||||
|
<A, B, C, D, E, F, G, H, I, J, K>(
|
||||||
|
value: A,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
fn8: (h: H) => I,
|
||||||
|
fn9: (i: I) => J,
|
||||||
|
fn10: (j: J) => K,
|
||||||
|
): K
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pipe: Pipe = (value: unknown, ...fns: Function[]): unknown => {
|
||||||
|
return fns.reduce((acc, fn) => fn(acc), value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compose Function (reverse order)
|
||||||
|
interface Compose {
|
||||||
|
<A>(): (a: A) => A
|
||||||
|
<A, B>(fn1: (a: A) => B): (a: A) => B
|
||||||
|
<A, B, C>(fn2: (b: B) => C, fn1: (a: A) => B): (a: A) => C
|
||||||
|
<A, B, C, D>(
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => D
|
||||||
|
<A, B, C, D, E>(
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => E
|
||||||
|
<A, B, C, D, E, F>(
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => F
|
||||||
|
<A, B, C, D, E, F, G>(
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => G
|
||||||
|
<A, B, C, D, E, F, G, H>(
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => H
|
||||||
|
<A, B, C, D, E, F, G, H, I>(
|
||||||
|
fn8: (h: H) => I,
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => I
|
||||||
|
<A, B, C, D, E, F, G, H, I, J>(
|
||||||
|
fn9: (i: I) => J,
|
||||||
|
fn8: (h: H) => I,
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => J
|
||||||
|
<A, B, C, D, E, F, G, H, I, J, K>(
|
||||||
|
fn10: (j: J) => K,
|
||||||
|
fn9: (i: I) => J,
|
||||||
|
fn8: (h: H) => I,
|
||||||
|
fn7: (g: G) => H,
|
||||||
|
fn6: (f: F) => G,
|
||||||
|
fn5: (e: E) => F,
|
||||||
|
fn4: (d: D) => E,
|
||||||
|
fn3: (c: C) => D,
|
||||||
|
fn2: (b: B) => C,
|
||||||
|
fn1: (a: A) => B,
|
||||||
|
): (a: A) => K
|
||||||
|
}
|
||||||
|
|
||||||
|
export const compose: Compose = (...fns: Function[]) => {
|
||||||
|
return (value: unknown) => fns.reduceRight((acc, fn) => fn(acc), value)
|
||||||
|
}
|
||||||
|
|
||||||
// TryCatch helper using Either
|
|
||||||
export const tryCatch = <A>(f: () => A): Either<A, Error> => {
|
export const tryCatch = <A>(f: () => A): Either<A, Error> => {
|
||||||
try {
|
try {
|
||||||
return right(f())
|
return right(f())
|
||||||
@ -14,6 +174,5 @@ export const tryCatch = <A>(f: () => A): Either<A, Error> => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option from nullable
|
|
||||||
export const fromNullable = <A>(a: A | null | undefined): Option<A> =>
|
export const fromNullable = <A>(a: A | null | undefined): Option<A> =>
|
||||||
a == null ? none : some(a)
|
a == null ? none : some(a)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user