Skip to content

Instantly share code, notes, and snippets.

@smolijar
Last active December 10, 2018 08:42
Show Gist options
  • Save smolijar/9fad33d2c8343d640069e30cb44fc5f4 to your computer and use it in GitHub Desktop.
Save smolijar/9fad33d2c8343d640069e30cb44fc5f4 to your computer and use it in GitHub Desktop.

Flow function type

👀 How lodash solves it?

It does not

  • long, unmaintainable, unconscious
  • junk code
  • limited number of args (usually 5 - 10)

💡 Intuitive code (that does not compile)

type Chain<In, Out, Tmp1 = any, Tmp2 = any> = []
    | [(arg: In) => Out]
    | [
        (arg: In) => Tmp1,
        (i: Tmp1) => Tmp2,
        ...Chain<Tmp2, Out>
    ];
declare function flow<In, Out>(...fns: Chain<In, Out>): Out

🤓 Nerd code

Types

type Lookup<T, K extends keyof any, Else=never> = K extends keyof T ? T[K] : Else
type Tail<T extends any[]> = 
  ((...t: T) => void) extends ((x: any, ...u: infer U) => void) ? U : never;
type Func1 = (arg: any) => any;
type ArgType<F, Else=never> = F extends (arg: infer A) => any ? A : Else;
type AsChain<F extends [Func1, ...Func1[]], G extends Func1[]= Tail<F>> =
  { [K in keyof F]: (arg: ArgType<F[K]>) => ArgType<Lookup<G, K, any>, any> };
type LastIndexOf<T extends any[]> =
  ((...x: T) => void) extends ((y: any, ...z: infer U) => void)
  ? U['length'] : never

declare function flow<F extends [(arg: any) => any, ...Array<(arg: any) => any>]>(
  ...f: F & AsChain<F>
): (arg: ArgType<F[0]>) => ReturnType<F[LastIndexOf<F>]>;

Usage

const badChain = flow(
  (x: number)=>"string", 
  (y: string)=>false, 
  (z: number)=>"oops"
); // error, boolean not assignable to number

const stringToString = flow(
  (x: string) => x.length, 
  (y: number) => y + "!"
); // okay
const str = stringToString("hey"); // it's a string

const tooFewParams = flow(); // error

See https://stackoverflow.com/questions/53173203/typescript-recursive-function-composition

🐒 Does it work?

(Now reported bug in Intellisense)

🐒 Does it hint?

❓ Are recursive types to be supported?

Probably no. See #27102

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment