TypeScript: Union array types do not infer common array prototype methods
TypeScript Version: 2.0.2rc
Code
const foo = (): number[] | string[] => Math.random() > 0.5 ? [0, 1, 2] : ["0", "1", "2"];
const bar = foo().filter((x) => Number(x) % 2 === 1);
Expected behavior: No errors.
Actual behavior:
Compiler gives: error TS2349: Cannot invoke an expression whose type lacks a call signature.
This issue seems to be array-specific. The following code compiles as expected:
const foo = (): { a } | { b } => Math.random() > 0.5 ? { a: true } : { b: true }
const bar = foo().hasOwnProperty('a');
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 15 (12 by maintainers)
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 typenumber[] | 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 forfilter
would result inpush(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 messageCannot invoke an expression whose type lacks a call signature.
Workaround:
(Note this unveils an expected second error in the snippet because
number % number
yieldsnumber
and .filter expectsboolean
)