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
filtermight be arguably safe,pushis not. So merging the signatures of(number[]|string[]).push(...)th same proposed forfilterwould 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
filterproperty 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 % numberyieldsnumberand .filter expectsboolean)