泛型函数子类型约束错误和混淆
Generic Function Subtype Constraint Error and Confusion
我正在考虑使用 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'.
似乎有一些子类型关系约束我无法完全理解(这个错误也没有给我太多好处)。希望对这些东西有更好的精神把握的人能给我一个体面的解释,这样我就不会对这种行为感到困惑(我确信这是正确的)。
"problem"是这样的: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. 会在此处抛出错误,这就是打字稿警告您的原因。
logFn<T extends (...args: any[]) => any>(fn: T): T
我们将收到类型 T
和 return 类型 T
。 return (a, b) => fn(a, b);
是一个有效的 return 类型,它确实扩展了 (...args: any[]) => any
但您如何确定传递给 fn
(T
) 的值与该签名匹配? (即它可能是 (...args: any[]) => any
的另一个不兼容的子类型)
不确定我是否解释得足够好,但这是我的理解
您的变通方法很好的原因是,通过添加 (...args: Parameters<T>) => ReturnType<T>
,您告诉编译器参数和 return 类型必须与传递的函数匹配,而不是 T
可以是任何其他函数定义
我正在考虑使用 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'.
似乎有一些子类型关系约束我无法完全理解(这个错误也没有给我太多好处)。希望对这些东西有更好的精神把握的人能给我一个体面的解释,这样我就不会对这种行为感到困惑(我确信这是正确的)。
"problem"是这样的: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. 会在此处抛出错误,这就是打字稿警告您的原因。
logFn<T extends (...args: any[]) => any>(fn: T): T
我们将收到类型 T
和 return 类型 T
。 return (a, b) => fn(a, b);
是一个有效的 return 类型,它确实扩展了 (...args: any[]) => any
但您如何确定传递给 fn
(T
) 的值与该签名匹配? (即它可能是 (...args: any[]) => any
的另一个不兼容的子类型)
不确定我是否解释得足够好,但这是我的理解
您的变通方法很好的原因是,通过添加 (...args: Parameters<T>) => ReturnType<T>
,您告诉编译器参数和 return 类型必须与传递的函数匹配,而不是 T
可以是任何其他函数定义