Consider an arbitrary amount of functions, each taking an argument, and returning a value (dont worry about what they do, not the point):
function toNumber(input: string): number {
return parseInt(input)
}
function toBoolean(input: number): boolean {
return input > 0
}
function toString(input: boolean): string {
return input.toString()
}
These functions could be chained (probably theres a better term in fp) like this, since each takes the previous one's return type as argument:
type Fn<I, O> = (input: I) => O
function chain(...fns: Fn<any, any>[]): Fn<any, any> {
return (input: any) => {
let result = input
for (const fn of fns) {
result = fn(result)
}
return result
}
}
const chained = chain(toNumber, toBoolean, toString)
const result = chained('5') // returns "true"
Is there a way in typescript to make the chain function type safe? Since we have an arbitrary amount of functions there has to be an arbitrary amount of generic arguments for this.
I could do something like this (fixed number of overloads):
declare function chain<S, T1>(fn: Fn<S, T1>): Fn<S, T1>
declare function chain<S, T1, T2>(fn1: Fn<S, T1>, fn2: Fn<T1, T2>): Fn<S, T2>
declare function chain<S, T1, T2, T3>(fn1: Fn<S, T1>, fn2: Fn<T1, T2>, fn3: Fn<T2, T3>): Fn<S, T3>
But is there a better way?