如何使用 Typescript 检查数组中泛型的实例

tom*_*ler 2 arrays instanceof typescript

我有一个接收数组的函数,但它们可以是不同的类型。根据我需要不同格式的类型:

public format(value: Foo[] | Bar[]) {
  // this does not work
  if (value instanceof Foo[]) ...
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以用来instanceof检查 Typescript 中是否有某个类的对象。

new Foo() instanceof Foo // true
Run Code Online (Sandbox Code Playgroud)

这也适用于检查我是否有数组。

new Array<Foo> instanceof Array // true
Run Code Online (Sandbox Code Playgroud)

但我无法检查我的数组是否实际上被输入到 Foo

new Array<Foo>() instanceof Array<Foo> 
// The right-hand side of an 'instanceof' expression must be of type 'any' 
// or of a type assignable to the 'Function' interface type.
Run Code Online (Sandbox Code Playgroud)

有没有办法显式检查数组值的类型?

jca*_*alz 9

Array<Foo>在运行时,和之间没有区别Array<Bar>;静态类型系统会从发出的 JavaScript 中删除,因此您拥有的只是一些 JavaScript 数组。因此,您需要编写自己的在运行时运行的测试,然后告诉编译器您在做什么,以便获得静态类型的好处。


一种方法是编写一些合适的用户定义类型保护函数,这可以让您执行此操作:

public format(value: Foo[] | Bar[]) {
    const isFooArray = isArrayOf(isInstanceOf(Foo));

    if (isFooArray(value)) {
        // true block
        for (const foo of value) {
            const f: Foo = foo; // okay
        }
    } else {
        // false block
        for (const bar of value) {
            const b: Bar = bar; // okay
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器知道,在 true 块内,value已从 缩小到Foo[] | Bar[]just Foo[],而在 false 块内,value已从 缩小到Foo[] | Bar[]just Bar[]。这与 的类型签名有关isFooArray(),它是通过组合其他两个函数isArrayOf()和的输出创建的类型保护isInstanceOf()

让我们检查一下它们的定义:

const isArrayOf = <T>(elemGuard: (x: any) => x is T) =>
    (arr: any[]): arr is Array<T> => arr.every(elemGuard);
Run Code Online (Sandbox Code Playgroud)

该函数采用单个数组元素的isArrayOf()类型保护函数,并返回一个调用数组的每个元素的新类型保护。如果所有元素都通过测试,那么您就有了一个受保护类型的数组。如果甚至有一个元素没有通过,那么你就没有通过。如果您愿意,您可以只检查一个元素,但是您可能会冒着意外将异构数组(如. 另请注意,这意味着空数组始终会通过测试;因此空数组将被视为 aa 。elemGuardelemGuardArray<Foo | Bar>Foo[][]Foo[] Bar[]

const isInstanceOf = <T>(ctor: new (...args: any) => T) =>
    (x: any): x is T => x instanceof ctor;
Run Code Online (Sandbox Code Playgroud)

isInstanceOf()函数只是将正常instanceof测试包装到适合与isArrayOf().

复合类型保护也是如此,它通过检查每个元素并进行检查const isFooArray = isArrayOf(isInstanceOf(Foo))来专门检查它正在检查的数组是否是 a 。Foo[]instanceof


好的,希望有帮助;祝你好运!

Playground 代码链接