S
S
Svyatoslav Khusamov2017-04-22 00:24:26
typescript
Svyatoslav Khusamov, 2017-04-22 00:24:26

What's the problem with combining Array types?

This code causes an error, the text of which is given below:

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

Error text:
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.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Stanislav Makarov, 2017-04-22
@khusamov

https://github.com/Microsoft/TypeScript/issues/10620 mhegazy
's comment about filter, which is basically the same as map:

This is a bit subtle, but number[] | string[] !=== (number | string)[]. The first one has an assertion 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 .

You can write your own typeguard that does the type narrowing for you:
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);
    }
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question