数组类型的类型防护

JeB*_*JeB 1 arrays types typescript

使用typeof非数组类型的类型防护非常简单(例如docs中的示例):

function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error(`Expected string or number, got '${padding}'.`);
}
Run Code Online (Sandbox Code Playgroud)

但是,涉及数组类型时,它变得更加复杂。我假设以下代码可以工作:

function join(array: number[] | string[]): string {
    if (typeof array[0] === 'number') {
        return foo(array);
    } else {
        return bar(array)
    }
}

function foo(n: number[]): string {
    return n.join();
}

function bar(s: string[]): string {
    return s.join();
}
Run Code Online (Sandbox Code Playgroud)

对我来说似乎很简单:期望的类型是数字数组或字符串数​​组。
如果数组中第一个元素的类型为,number则数组的类型为number[]。否则,这是一个字符串数组。

不幸的是,TypeScript编译器不是很聪明,并且出现编译错误:

类型'number []的参数| 字符串[]'不可分配给类型为'字符串[]'的参数

我该如何运作?

Pie*_*eau 10

JeB 的回答对我来说是一个非常好的开始,但我需要一些更强大的东西,因为我必须处理任意输入。这是我想出的:

function isNumberArray(value : unknown) : value is number[] {
    if (!Array.isArray(value)) {
        return false;
    }

    if (value.some((v) => typeof v !== "number")) {
        return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)


JeB*_*JeB 6

答案是用户定义的类型防护

您可以定义自己的类型保护,它将确定数组是否为数字数组:

function isNumbers(array: number[] | string[]): array is number[] {
    return typeof array[0] === 'number'
}
Run Code Online (Sandbox Code Playgroud)

在此处阅读有关用户定义类型防护的更多信息。

以下是您的代码的有效示例:

function join(array: number[] | string[]): string {
    if (isNumbers(array)) {
        return foo(array);
    } else {
        return bar(array)
    }
}

function foo(n: number[]): string {
    return n.join();
}

function bar(s: string[]): string {
    return s.join();
}

function isNumbers(array: number[] | string[]): array is number[] {
    return typeof array[0] === 'number'
}
Run Code Online (Sandbox Code Playgroud)

TypeScript游乐场示例