Получение типа последней функции из произвольного количества замыканий

#typescript

#typescript

Вопрос:

Рассмотрим функцию:

 const f = a => b => ... x => { return somevalue }
  

Как мне получить тип только для последней функции typeof x => { return somevalue } , не зная общего количества замыканий?

Моя первоначальная мысль заключается в том, что нам нужно создать тип, который использует рекурсию и проверку условного типа, пока мы не дойдем до конца. Однако я не уверен, поддерживает ли typescript рекурсивные типы для такого рода задач.

Ответ №1:

Рекурсивные условные типы будут поддерживаться в TypeScript 4.1, когда он выйдет. На данный момент это доступно в typescript@next . Тогда вы сможете написать что-то вроде

 type LastFunc<T extends (...args: any) => any> =
    T extends (...args: any) => infer R ? 
    R extends (...args: any) => any ? LastFunc<R> : T : never;
  

и использовать его в своей f функции:

 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
  

Игровая площадка ссылка на код


До тех пор вы можете использовать либо неподдерживаемый обходной путь для получения такого поведения, например, следующую вещь с отложенным поиском объекта, которая сбивает с толку и раздражает:

 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
  

или вы можете использовать только поддерживаемые функции, разворачивая цикл до фиксированной глубины, что является избыточным и раздражающим:

 type LastFunc<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF0<R> : T : never;
type LF0<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF1<R> : T : never;
type LF1<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF2<R> : T : never;
type LF2<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF3<R> : T : never;
type LF3<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF4<R> : T : never;
type LF4<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF5<R> : T : never;
type LF5<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF6<R> : T : never;
type LF6<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF7<R> : T : never;
type LF7<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF8<R> : T : never;
type LF8<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LF9<R> : T : never;
type LF9<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? LFX<R> : T : never;
type LFX<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R extends (...args: any) => any ? R : T : never;
  

Игровая площадка ссылка на код


Лично я бы на вашем месте просто подождал до TS4.1. Хорошо, надеюсь, это поможет; удачи!