https://github.com/Microsoft/TypeScript/issues/10620
Комментарий
mhegazy о filter, с которым в общем-то такая же ситуация, что и с map:
This is a bit subtle, but number[] | string[] !=== (number | string)[]. The first one has an assert on homogeneity, while the second does not. just as in the example noted above by @kaotik4266, [0, "1", 2] is not of type number[] | string[].
There is not a meaningful way to describe the general case for merging unmatching signatures; while filter might be arguably safe, push is not. So merging the signatures of (number[]|string[]).push(...) th same proposed for filter would result in push(a: number | string); which means that we are treating the original type as (number | string)[], which is not type safe.
So the general case, is there is no common signatures between the two types, and thus the resulting union type does have a filter property but it does not have a signature, and hence the error message Cannot invoke an expression whose type lacks a call signature.
Можете написать себе свой собственный тайпгвард, который выполнит вам сужение типа:
function isNumbers(arr: number[] | string[]): arr is number[] {
return arr.length === 0 || // В случае нулевой длины тип элемента массива нам не важен, примем его за number
typeof arr[0] === "number"; // Либо проверим фактический тип первого элемента. Этого должно быть
// достаточно, т.к. в типе 'arr' декларируется однородность массивов
}
function getHandler(handlers: number[] | string[]): number[] | string[] {
if (isNumbers(handlers)) {
return handlers.map(handler => handler);
} else {
return handlers.map(handler => handler);
}
}