我在玩使用 TypeScript 的简单包装函数的想法。我最终得到了一些与以下内容有关的东西:
export function logFn<T extends (...args: any[]) => any>(
fn: T,
): (...args: Parameters<T>) => ReturnType<T> {
const log = (...args: Parameters<T>): ReturnType<T> => {
console.log('log')
return fn(...args)
}
return log
}
这有效并且编译器很高兴。我的问题是关于我最初的尝试,它看起来更像这样
export function logFn<T extends (...args: any[]) => any>(
fn: T,
): T {
const log: T = (...args) => {
console.log('log')
return fn(...args)
}
return log
}
这给了我一个错误
log
带有错误的变量声明:Type '(...args: any[]) => any' is not assignable to type 'T'.
'(...args: any[]) => any' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '(...args: any[]) => any'.
似乎有一些我无法完全理解的子类型关系约束(这个错误也没有给我带来太多好处)。希望对这些东西有更好的精神理解的人能给我一个体面的解释,这样我就不会被这种行为弄糊涂(我确信这是正确的)。
最佳答案
“问题”是这样的:T extends (...args: any[]) => any
如果您看到以下版本,它会更加直观:
export function logFn<T extends (...args: any[]) => any>(fn: T): T {
return (a, b) => fn(a, b);
}
你会看到错误成立
Type '(a: any, b: any) => any' is not assignable to type 'T'. '(a: any, b: any) => any' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '(...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. 会在这里抛出一个错误,这就是 typescript 警告你的原因。
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
可以是任何其他函数定义
关于typescript - 泛型函数子类型约束错误和混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58209952/