'Type guards for types of arrays

Using typeof type guards for non-array types is pretty straightforward (example from the 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}'.`);
}

However, when it comes to array types it gets more complicated. I would assume that the following code would work:

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();
}

Seems quite simple to me: the expected type is either array of numbers or array of strings.
If the type of the first element in the array is number then the array is of type number[]. Otherwise, this is a strings array.

Unfortunately, TypeScript compiler is not that smart and I get a compilation error:

Argument of type 'number[] | string[]' is not assignable to parameter of type 'string[]'

How do I make it work?



Solution 1:[1]

JeB's answer was a very good start for me but I needed something a little more robust because I have to deal with arbitrary input. Here's what I came up with:

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

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

    return true;
}

Solution 2:[2]

Here is an example I use for string array. I guess you could make it generic and test for any type:

export const isStringArray = (value: unknown) => {
  return Array.isArray(value) && value.every((val) => typeof val === "string");
};

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Pier-Luc Gendreau
Solution 2 cham