Recursive conditional types are set to debut in TypeScript 4.1. In the meantime, you can access this feature by using typescript@next
. Once available, you'll be able to define something like:
type LastFunc<T extends (...args: any) => any> =
T extends (...args: any) => infer R ?
R extends (...args: any) => any ? LastFunc<R> : T : never;
You can apply it to your function f
as follows:
declare const somevalue: SomeValue;
const f = (a: any) => (b: any) => (c: any) => (d: any) => (x: any) => { return somevalue }
type LastFuncF = LastFunc<typeof f>; // type LastFuncF = (x: any) => SomeValue
Playground link to code
In the interim, there are two ways to achieve similar results. The first is a workaround that may not be officially supported but gets the job done:
type LastFunc<T extends (...args: any) => any> =
T extends (...args: any) => infer R ? {
0: LastFunc<Extract<R, (...args: any) => any>>, 1: T
}[R extends (...args: any) => any ? 0 : 1] : never
The second method involves manually unrolling the loop to a fixed depth which can be tedious and repetitive:
type LastFunc<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF0<R> : T : never;
// Additional LFX definitions...
Playground link to code
If I were in your shoes, I'd recommend waiting for TypeScript 4.1's release. Best of luck with your coding endeavors!