Bug报告
🔎 搜索词
内置函数、接口、可调用、构造器、narrow、不安全
🕗 版本与回归信息
这个问题至少可以追溯到3.3.3版本。
- 我尝试了所有版本,并查阅了关于函数的常见问题解答条目。
⏯ Playground链接
带有相关代码的Playground链接
💻 代码
type OnlyCallable = (...args: any) => any;
type OnlyConstructorCallable = new (...args: any) => any
type AnyFunction = OnlyCallable | OnlyConstructorCallable
function call(func: AnyFunction) {
// @ts-expect-error Makes sense
func();
// @ts-expect-error Makes sense
new func();
// @ts-expect-error Makes sense
const a: OnlyCallable = func;
// @ts-expect-error Makes sense
const b: OnlyConstructorCallable = func;
// Why is this not an error?
const c: Function = func;
a();
// @ts-expect-error Makes sense
new a();
new b();
// @ts-expect-error Makes sense
b();
// Why is this not an error?
c();
// But this is?
new c();
}
🙁 实际行为
Function
似乎是一个比 (...args: any) => any
更不安全的版本,因为它允许将 AnyFunction
赋值给它。
🙂 预期行为
Function
应该表现得像 (...args: any) => any
或 AnyFunction
,甚至像 OnlyCallable & OnlyConstructorCallable
。更糟糕的是,
function foo(value: unknown) {
if (typeof value === 'function') {
// `value` is narrowed to `Function`
value();
}
if (value instanceof Function) {
// `value` is narrowed to `Function`
value();
}
}
// @ts-expect-error Makes sense
Promise()
// No type error but this will throw at runtime
foo(Promise)
9条答案
按热度按时间lo8azlld1#
这是预期的行为;我们使用的术语是“未指定类型的函数调用”。可以添加一个标志来关闭此功能,但这种行为可以追溯到TypeScript 0.8,而且我还没有看到关于它的很多反馈。
ztigrdn82#
让我觉得允许无类型函数可调用的启发式是有道理的,因为绝大多数“函数”都可以在不使用“new”的情况下调用。我主要反对的是允许上面定义的
OnlyConstructorCallable
和AnyCallable
被分配给Function
。这种错误类别的感觉类似于通过将ReadonlyArray
分配给Array
而允许的错误类别。我认为禁止这样的赋值不会影响到很少的用户,同时也会减少
Function
的特殊、神奇类型。实现这一点的最简单方法是将Function
定义为(...args: any) => any
,但我觉得这一定在之前就被提出过了。有没有好的例子说明这样做是不理想的?zu0ti5jz3#
Function
作为一个可调用对象的有效赋值目标是不可协商的部分。Function
本身与常规函数的关系与string
与String
,number
与Number
等的关系相同。w8f9ii694#
Function
是一个有效的可调用对象的赋值目标new () => T
在没有标准调用签名的情况下,技术上来说并不是可调用的,尽管如此 - 例如,Promise();
在没有new
的情况下会抛出异常,而且在没有实际尝试调用它的情况下,没有办法知道这一点(仅将某物作为Function
类型输入)。7fhtutme5#
构造函数仍然具有
bind
/call
/apply
,而Function
的作用是提供这些功能。iugsix8n6#
根据我所知,在类构造函数上调用这些方法总是会导致运行时错误。你需要使用
Reflect.construct()
来调用类的构造函数。1aaf6o9v7#
是的,对于那些肯定存在但肯定不可调用的东西(DOM中的非用户可调用的HTML元素构造函数也存在这个问题),如何进行推理确实令人困惑。从技术上讲,你可以调用
ctor.bind.bind(...
,所以它就在那里...eyh26e7m8#
我认为我已经说服自己,当前状态是可以接受的(好吧,至少没有比其他事情更糟糕)。既然这是允许的:
我想调用和不调用
new
之间的不对称仍然让我有些困扰,但我不认为允许使用Function
调用new
会带来太多实际好处。请随意关闭或保留以供讨论。
mzmfm0qo9#
据我所知,在类构造函数上调用这些方法总是会导致运行时错误。
.bind
可以与类构造函数安全地一起使用。示例: