khusamov
@khusamov
ReactJS, NodeJS, TypeScript, Sencha ExtJS

Что за проблема в объединении типов Array?

Данный код вызывает ошибку, текст которой дан ниже:

function getHandler(handlers: number[] | string[]): any {
    return handlers.map(handler => handler);
}


Текст ошибки:

error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{ (this: [string, string, string, string, string], callbackfn: (value: string, index: number, ...' has no compatible call signatures.
  • Вопрос задан
  • 1983 просмотра
Решения вопроса 1
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);
    }
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы