Maybe I'm not following but if the higher order function returns a function with any parameters, that when called will return the result of the function passed in, passing through arguments - can't you just instead return the function passed in? Then the generic typing is pretty simple and I don't see what else you'd need for typing.
function higherOrderFunction<T>(fn: T): T {
// do something
return fn;
}
function fun(x: number, y: string) { return `${x}${+y}`; }
const higherOrderFunctionWithFunction = higherOrderFunction(fun);
console.log(higherOrderFunctionWithFunction(1, 3)) // error can't assign number to string
Edit:
If your higher order function were the below then that would change things and I'd change my answer. But you have the // do something before the return so going off your example it looks like you may as well just return fn...
function higherOrderFunction<T>(fn: T): T {
return (...args) => {
// do something common on every call
return fn(...args);
};
}
Edit2:
For the above scenario, if you really need to wrap fn in another function - here is the only way I was able to get the type checks you're looking for, with no other errors. I had to use type assertion for the return of your higher order function to assert that T is being returned and it's not instantiated as a different subtype... Can't say I'm 100% understanding the issue there in this specific case but it's related to this: could be instantiated with a different subtype of constraint 'object'
function higherOrderFunction<T extends (...args: any[]) => unknown>(fn: T): T {
return ((...args) => {
// do something common on every call
return fn(...args);
}) as T;
}
function fun(x: number, y: string) { return `${x}${+y}`; }
const higherOrderFunctionWithFunction = higherOrderFunction(fun);
console.log(higherOrderFunctionWithFunction(1, 3)) // error can't assign number to string
Edit3:
Looking at your answer, I like it better and upvoted, I think you got it...