关于javascript:如何开始理解类型…args:any [])=> any

How to go about understanding the type …args: any[]) => any

我正在阅读类验证器库的代码,并且其中包含以下isInstance方法:

1
2
3
4
5
6
7
8
/**
 * Checks if the value is an instance of the specified object.
 */

isInstance(object: any, targetTypeConstructor: new (...args: any[]) => any) {
    return targetTypeConstructor
        && typeof targetTypeConstructor ==="function"
        && object instanceof targetTypeConstructor;
}

关于如何理解类型new (...args: any[]) => any的任何想法? 这是我第一次看到这种构造...


让我们将类型减少为更容易理解的更小,更小尺寸的块,然后重新构建完整的块。

首先,让我们放下new的注意力,专注于定义的后半部分:

(...args: any[]) => any

接下来,让我们暂时忘记参数:

() => any

希望这是返回类型any的函数。

接下来,我们可以重新添加参数:

(...args: any[]) => any

...args: any[]使用的是Rest Parameters构造,该构造本质上表示可以提供any类型的任何数量的参数。因为存在数量未知的any参数,所以参数的类型是any的数组。

因此,现在希望这是一个可以接受任意数量的参数(any类型)并返回any类型的函数是有意义的。

最后,我们可以添加new关键字来获得:

new (...args: any[]) => any

此处的new关键字指定可以将此函数视为类构造函数,并使用new关键字进行调用。

这给我们提供了整个图片,该函数是一个可以接受返回类型any的任意数量的参数(类型为any的函数),并且可以用作带有new关键字的构造函数。

当在API上下文中使用时,它实际上允许您将任何类构造函数传递给该函数。


分解成碎片:

new
TypeScript中的此关键字为给定属性指定构造函数的外观。很好的解释在这里:https://stackoverflow.com/a/39623422/1678614。

(...args: any[]) => any
此语法描述了函数类型(构造函数是函数)。现在忽略...部分。

...
是ES6点差运算符。它是一一列出所有数组元素的快捷方式。

any[]
表示args是一个数组,它的元素可以是任何类型。

=> any
指定函数的返回类型。在这种情况下,它允许构造函数返回任何类型。


意味着参数targetTypeConstructor是一个接受参数的函数,可以用作构造函数(可以与new关键字一起使用并创建实例)。您可以传递一个非抽象的简单函数或类。

有关更多信息,您可以在Typescript Playground中查看示例。


1
new (...args: any[]) => any

此类型指定一个函数,该函数接受any类型的任意数量的参数,返回any值,并且可以用new调用。

构造函数是一种特殊类型的函数,在运行时使用new关键字强制执行调用,但是在TypeScript中,可以静态检测到该函数,因此targetTypeConstructor将任意构造函数指定为isInstance()的第二个参数。

为此,检查似乎是多余的

1
typeof targetTypeConstructor ==="function"

因为targetTypeConstructor : new (...args: any[]) => any已在TypeScript编译时强制执行该操作。

如果传递的值是null,则它已经被targetTypeConstructor && ...条件使之无效,这在运行时对于防止object instanceof targetTypeConstructor由于步骤而实际上是null时防止object instanceof targetTypeConstructor抛出TypeError是必要的4
在ECMAScript规范的§12.10.4中:

12.10.4 Runtime Semantics: InstanceofOperator ( V, target )

  • If Type(target) is not Object, throw a TypeError exception.
  • Let instOfHandler be ? GetMethod(target, @@hasInstance).
  • If instOfHandler is not undefined, then

    a. Return ToBoolean(? Call(instOfHandler, target, ? V ?)).

  • If IsCallable(target) is false, throw a TypeError exception.
  • Return ? OrdinaryHasInstance(target, V).
  • NOTE

    Steps 4 and 5 provide compatibility with previous editions of ECMAScript that did not use a @@hasInstance method to define the instanceof operator semantics. If an object does not define or inherit @@hasInstance it uses the default instanceof semantics.