在TypeScript中检测联合类型参数是数组还是数组数组

时间:2018-09-20 21:00:06

标签: typescript

我有一个名为Bounds的接口,还有一个Sprite类,其类型为bounds的字段Bounds[][]Sprite的{​​{1}}的联合类型参数为constructor。如果参数的类型为Bounds[]|Bounds[][],我想将其包装在一个数组中:

Bounds[]

此代码有效,但是TypeScript编译器分别给我第二和第三次分配这些错误:

class Sprite {
    constructor(bounds: Bounds[]|Bounds[][]) {
        if (!bounds) {
            this.bounds = [[ /* some default value */ ]];
        } else {
            if (!bounds.length) {
                throw new Error('Argument \'bounds\' must not be empty.');
            }

            if (!Array.isArray(bounds[0])) {
                this.bounds = [bounds];
            } else {
                this.bounds = bounds;
            }
        }
    }

    bounds: Bounds[][];
}

我如何明确告诉编译器“此时Type '(Bounds[] | Bounds[][])[]' is not assignable to type 'Bounds[][]'. Type 'Bounds[] | Bounds[][]' is not assignable to type 'Bounds[]'. Type 'Bounds[][]' is not assignable to type 'Bounds[]'. Type 'Bounds[]' is not assignable to type 'Bounds'. Property 'x' is missing in type 'Bounds[]'. Type 'Bounds[] | Bounds[][]' is not assignable to type 'Bounds[][]'. Type 'Bounds[]' is not assignable to type 'Bounds[][]'. Type 'Bounds' is not assignable to type 'Bounds[]'. Property 'length' is missing in type 'Bounds'. bounds类型还是Bounds[]类型或使用正确的if语句,以便编译器可以到达这个结论本身吗?

1 个答案:

答案 0 :(得分:2)

如果您想帮助编译器进行推理,可以使用自定义类型防护:

const isArrayOfArrays = <T>(b: T[] | T[][]):b is T[][] => Array.isArray(b[0]);
class Sprite {
    constructor(bounds: Bounds[]|Bounds[][]) {
        if (!bounds) {
            this.bounds = [[ /* some default value */ ]];
        } else {
            if (!bounds.length) {
                throw new Error('Argument \'bounds\' must not be empty.');
            }
            if (!isArrayOfArrays(bounds)) {
                this.bounds = [bounds];
            } else {
                this.bounds = bounds;
            }
        }
    }

    bounds: Bounds[][];
}

类型防护程序可在任何此类情况下重用。

懒惰的方法是只使用类型断言,然后告诉编译器您对类型的了解:

class Sprite {
    constructor(bounds: Bounds[] | Bounds[][]) {
        if (!bounds) {
            this.bounds = [[ /* some default value */]];
        } else {
            if (!bounds.length) {
                throw new Error('Argument \'bounds\' must not be empty.');
            }
            if (!Array.isArray(bounds[0])) {
                this.bounds = [bounds as Bounds[]];
            } else {
                this.bounds = bounds as Bounds[][];
            }
        }
    }

    bounds: Bounds[][];
}