I need to be able to infer the argument type of a function that is passed as a parameter, based on another parameter where the type is known. It's kinda hard to explain so I wrote a little demo, reproduced here:
interface UnaryFunction<In, Out> {
(arg: In): Out
}
interface WithNumber<In, Out> extends UnaryFunction<In, Out> {
num: number
}
function testExtends<Arg, Fn extends UnaryFunction<Arg, any>>(arg: Arg, fn: Fn): Fn {
return fn;
}
function testInferred<Arg, Out>(arg: Arg, fn: UnaryFunction<Arg, Out>): typeof fn {
return fn
}
function mapWithCaller<From, To>(morphism: UnaryFunction<From, To>): WithNumber<From, To> {
return Object.assign((x: From) => morphism(x), {num: 5})
}
// Error: property length does not exist
testExtends('1', mapWithCaller(x => x.length)).num
// Error: property num does not exist
testInferred('1', mapWithCaller(x => x.length)).num
As you can see, with testExtends the return type of the function is preserved, while with testInferred the parameter type of the passed function is inferred.
I need to be able to combine the best of both worlds, and it's driving me crazy, is this not possible at all? Is it a bug? By design?