«Проблема» заключается в следующем: T extends (...args: any[]) => any
Это более наглядно, если вы видите следующую версию:
export function logFn<T extends (...args: any[]) => any>(fn: T): T {
return (a, b) => fn(a, b);
}
Вы увидите, что ошибка удерживается
Тип '(a: любой, b: любой) => любой "нельзя назначить типу" T ". '(a: any, b: any) => any' присваивается ограничению типа 'T', но экземпляр T может быть создан с другим подтипом ограничения '(... args: any []) => any '.
Оба из приведенных ниже действительны до T extends (...args: any[]) => any
logFn((a, b) => a + b)
logFn((a, b, c) => c)
Но если вы вернетесь к приведенному мною примеру, внутреннее определение будет выглядеть так:
return (a, b) => fn(a, b);
Так что вариант 2. выдаст здесь ошибку, поэтому машинопись предупреждает вас об этом.
logFn<T extends (...args: any[]) => any>(fn: T): T
Мы собираемся получить тип T
и вернуть тип T
. return (a, b) => fn(a, b);
является допустимым типом возвращаемого значения, оно распространяется (...args: any[]) => any
, но как вы можете быть уверены, что значение, переданное в fn
(T
), соответствует этой подписи? (т. е. это может быть другой несовместимый подтип (...args: any[]) => any
)
Не уверен, что я объяснил достаточно хорошо, но это мое понимание
Причина, по которой вы можете обойтись, заключается в добавлении (...args: Parameters<T>) => ReturnType<T>
вы говорите компилятору, что параметры и возвращаемые типы должны совпадать с типами передаваемой функции, в отличие от T
, который может быть любым другим определением функции