Type guards for types of arrays
Solution 1
The answer is User-Defined Type Guards.
You can define a type guard of your own that will determine whether the array is array of numbers or not:
function isNumbers(array: number[] | string[]): array is number[] {
return typeof array[0] === 'number'
}
Read more about user defined type guards here.
The following is a working example of your code:
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'
}
TypeScript playground example.
Solution 2
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;
}
JeB
Updated on July 28, 2022Comments
-
JeB almost 2 years
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 isnumber
then the array is of typenumber[]
. 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?