I have created functions called pipe
and compose
which can combine two functions into a new one, with the only difference being the order in which they are called when applied to an argument.
Although both functions are generic, I am having trouble ensuring that the resulting function is strongly typed in TypeScript.
Here are my questions:
- Is the incorrect inference of the function type a limitation of the language, or am I making a mistake in my implementation?
- If it is possible in TypeScript, how can I correct this issue?
function pipe<X, Y, Z>(first: (x: X) => Y): (f2: (y: Y) => Z) => (x: X) => Z {
return function (second: (y: Y) => Z): (x: X) => Z {
return function (x: X): Z {
return second(first(x));
};
}
}
function compose2<X, Y, Z>(second: (y: Y) => Z): (f2: (x: X) => Y) => (x: X) => Z {
return function (first: (x: X) => Y): (x: X) => Z {
return function (x: X): Z {
return second(first(x));
};
}
}
Usage
function numToStr(n: number): string { return n.toString(); }
function strToLen(s: string): number { return s.length; }
// Currently inferred as (x: number) => unknown
// Expected to be (x: number) => number
const f1 = pipe(numToStr)(strToLen);
// Currently inferred as (x: unknown) => number
// Expected to be (x: number) => number
const f2 = compose(strToLen)(numToStr);