为什么不管用?
const x: unknown[] = ['x', 32, true]; // OK
const y: (...args: unknown[]) => unknown = (xx: number) => {}; // ERROR
// Type '(xx: number) => void' is not assignable to type '(...args: unknown[]) => unknown'.
// Types of parameters 'xx' and 'args' are incompatible.
// Type 'unknown' is not assignable to type 'number'. ts(2322)
我的目标是确保y
是任何可运行的函数。我试图不使用any
。希望提高我对unknown
在这种情况下如何工作的理解。
2条答案
按热度按时间js5cn81o1#
函数类型在其参数类型中是 * 逆变 * 的;更多细节参见Difference between Variance, Covariance, Contravariance and Bivariance in TypeScript,convariance表示可赋值性的方向翻转;如果
T
可赋值给U
,则(...u: U) => void
可赋值给(...t: T) => void
,反之则不可。这是类型安全所必需的。请描绘数据流的方向:如果你想要水果,我可以给你一个苹果,但是如果你想要吃你所有水果的东西,我不能给你只吃苹果的东西。函数类型
(xx: number) => void
等价于(...args: [number]) => void
,你不能把它赋值给(...args: unknown[]) => void
。是的,[number]
可以赋值给unknown[]
,但这不是我们关心的方向,因此你的赋值是不安全的。如果这样做有效:这样,你就可以用任何一组参数调用
y()
,而不会出现编译器错误,但却遇到了一个运行时错误:将输入参数列表扩展到
unknown[]
会使函数类型变得非常窄,因为大多数函数并不接受所有可能的参数列表。因此,如果你真的想要一个类型,任何函数都应该被赋值给它,你需要将输入参数列表 * 缩小 * 到一个不能接受 * 任何 * 输入的类型,如下所示:
这是因为
SomeFunction
本质上是不可调用的(当然,它应该是不可调用的; ms/TS#48840有一个未解决的bug).如果我向你请求一个我不会调用的函数,你可以放心地交给我任何函数.相反,如果你交给我一个函数,我不知道它接受什么参数,我最好不要尝试调用它.这是可行的,但是......它有点没用。一旦你有了
y
,你就不能用它做任何事情:对于您问题中的用例,我想这很好,因为您将这些不可调用的函数传递给非TypeScript代码,而这些代码不了解或不考虑我们的类型安全规则。
不过,对于其他可能正在阅读的人来说,* 验证 * 一个值可以被赋给一个类型而不 * 扩展 * 它可能会更有用,所以我们可以使用
satisfies
操作符来检查它是否符合该类型,而不是将y
注解为SomeFunction
:它会编译(但是如果你写的是
const y = "oops" satisifies SomeFunction
,就会失败),而y
仍然是(xx: number) => string
,所以你仍然可以称之为:Playground代码链接
osh3o9ms2#
为什么不管用?
下面是一个错误:
因为这是一个错误的相同原因:
简化原因:如果不先检查unknown的运行时值,就不能将其赋给其他任何对象。