You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript函数extends unknown函数签名返回false原因及解法

为什么Bar的计算结果为false

核心原因是TypeScript函数类型检查遵循参数逆变规则:
判断函数A extends 函数B是否成立时,参数位置的类型兼容是反向校验的:A的每个参数类型必须比B对应位置的参数类型范围更宽(是B参数类型的父类型),否则兼容不成立。
Bar里用来匹配的目标类型是(...args: unknown[]) => unknown,这个类型要求函数必须能接收任意类型、任意数量的传入参数;但被检查的(str: string) => void只能接收string类型参数,传其他类型就会报错,不满足参数兼容要求,自然返回false。
而Foo返回true是因为any是TS的特殊类型,会直接绕过严格的类型兼容性校验,所以所有函数都能匹配(...args: any[]) => any,但这种写法确实不符合TS的最佳实践,会引入类型安全漏洞。

无any的最优实现方案

利用类型兼容规则调整匹配用的函数类型即可,不需要用any:

type IsFunction<T> = T extends (...args: never[]) => unknown ? true : false

效果验证

type Foo = IsFunction<(str: string) => void> // true,和原Foo表现完全一致
type TestNoArg = IsFunction<() => number> // true,无参函数也能正确识别
type TestObj = IsFunction<{ id: number }> // false,非函数类型正确返回false
type TestPrimitive = IsFunction<boolean> // false

实现原理

  • 参数位置用never[]:never是TS里所有类型的子类型,按照参数逆变规则,任何合法函数的参数类型范围都比never[]宽,天然满足参数兼容要求
  • 返回值位置用unknown:unknown是TS的顶层类型,所有类型的返回值都满足返回值协变的兼容要求

整个实现没有用到any,完全走严格类型检查,没有安全隐患。如果需要额外区分类构造函数(带new调用签名的类型),可以在这个基础上再加一层构造签名的判断,普通函数检测场景下这个写法完全够用。


内容的提问来源于stack exchange,提问作者TrevTheDev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 10:48:15