Skip to content

Instantly share code, notes, and snippets.

@jeroenvanwijgerden
Last active April 8, 2024 14:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeroenvanwijgerden/1435d87aae4729b79196598e9588aed3 to your computer and use it in GitHub Desktop.
Save jeroenvanwijgerden/1435d87aae4729b79196598e9588aed3 to your computer and use it in GitHub Desktop.
chain.ts
type Compose = {
<A, B>(
fn1: (x: A) => B
): (arg: A) => B;
<A, B, C>(
fn1: (x: A) => B,
fn2: (x: B) => C
): (arg: A) => C;
<A, B, C, D>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D
): (arg: A) => D;
<A, B, C, D, E>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E
): (arg: A) => E;
<A, B, C, D, E, F>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F
): (arg: A) => F;
<A, B, C, D, E, F, G>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G
): (arg: A) => G;
<A, B, C, D, E, F, G, H>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H
): (arg: A) => H;
<A, B, C, D, E, F, G, H, I>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I
): (arg: A) => I;
<A, B, C, D, E, F, G, H, I, J>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J
): (arg: A) => J;
<A, B, C, D, E, F, G, H, I, J, K>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K
): (arg: A) => K;
<A, B, C, D, E, F, G, H, I, J, K, L>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L
): (arg: A) => L;
<A, B, C, D, E, F, G, H, I, J, K, L, M>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M
): (arg: A) => M;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N
): (arg: A) => N;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N,
fn14: (x: N) => O
): (arg: A) => O;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N,
fn14: (x: N) => O,
fn15: (x: O) => P
): (arg: A) => P;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q>(
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N,
fn14: (x: N) => O,
fn15: (x: O) => P,
fn16: (x: P) => Q
): (arg: A) => Q;
};
const compose: Compose = (...fns: ((arg: any)=>any)[]) => {
return (initial: any) => fns.reduce((acc, fn) => fn(acc), initial);
}
type Chain = {
<A>(
initialValue: A
): A;
<A, B>(
initialValue: A,
fn1: (x: A) => B
): B;
<A, B, C>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C
): C;
<A, B, C, D>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D
): D;
<A, B, C, D, E>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E
): E;
<A, B, C, D, E, F>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F
): F;
<A, B, C, D, E, F, G>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G
): G;
<A, B, C, D, E, F, G, H>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H
): H;
<A, B, C, D, E, F, G, H, I>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I
): I;
<A, B, C, D, E, F, G, H, I, J>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J
): J;
<A, B, C, D, E, F, G, H, I, J, K>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K
): K;
<A, B, C, D, E, F, G, H, I, J, K, L>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L
): L;
<A, B, C, D, E, F, G, H, I, J, K, L, M>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M
): M;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N
): N;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N,
fn14: (x: N) => O
): O;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N,
fn14: (x: N) => O,
fn15: (x: O) => P
): P;
<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q>(
initialValue: A,
fn1: (x: A) => B,
fn2: (x: B) => C,
fn3: (x: C) => D,
fn4: (x: D) => E,
fn5: (x: E) => F,
fn6: (x: F) => G,
fn7: (x: G) => H,
fn8: (x: H) => I,
fn9: (x: I) => J,
fn10: (x: J) => K,
fn11: (x: K) => L,
fn12: (x: L) => M,
fn13: (x: M) => N,
fn14: (x: N) => O,
fn15: (x: O) => P,
fn16: (x: P) => Q
): Q;
};
// You would think (hope) that `chain` could be implemented using `compose`, but typechecking isn't smart enough yet.
const chain: Chain = (initial: any, ...fns: ((arg: any)=>any)[]) => {
return fns.reduce((acc, fn) => fn(acc), initial);
};
// For a function F that produces a side-effect involving its single parameter X but does not return X;
// you can wrap F in `link`, adapting it so X is returned.
// Note: type A will primarily be determined by F. If F specified a type for its first parameter,
// then A will become that type. Because of this, unfortunately something like
// link(console.log)
// will be seen as returning an `any` type.
// If F does not explicitly provide a type for its parameter, then A will be inferred from the usage of
// the function returned by link (the adapted version of F).
export const link = <A>(f: (arg: A) => unknown) => {
return (value: A) => {
f(value);
return value
};
};
/*
chain(
[1,2,3],
link(x=>x.push(1)),
x=>x.length
)
chain(
[1,2,3],
compose(
link(x=>x.push(4)),
x=>x.length
)
)
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment