Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibly empty tuple confuses map and reduce methods #38514

Closed
Treora opened this issue May 12, 2020 · 1 comment
Closed

Possibly empty tuple confuses map and reduce methods #38514

Treora opened this issue May 12, 2020 · 1 comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed

Comments

@Treora
Copy link

Treora commented May 12, 2020

(feel free to improve the issue title)

TypeScript Version: 4.0.0-dev.20200512 (also tested on 3.8.3 and 3.9.2)

Search Terms: empty tuple union never map reduce filter forEach

Code

function f(a: [number, number] | [number] | []) {
    a.map(x => x+3)
    a.reduce((acc, next) => acc+next, 0)
    a.filter(x => x > 5)
    a.forEach(x => x.toString())
}

Expected behavior:

No type checking errors: when a is an empty tuple at runtime, none of the callbacks would ever be invoked, so their arguments could safely be inferred to be number (I guess that internally, number and never would have to combine to become number).

Actual behavior:

The a.map on line 2 infers the type of x to be any, and raises an error about incompatible signatures:

This expression is not callable.
Each member of the union type '((callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: number, index: number, array: number[]) => U, thisArg?: any) => U[]) | ((callbackfn: (value: never, index: number, array: never[]) => U, thisArg?: any) => U[])' has signatures, but none of those signatures are compatible with each other.(2349)

Likewise, the a.reduce on line 3 infers the types of acc and next to be any, and raises an error about incompatible signatures:

This expression is not callable.
Each member of the union type '{ (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number): number; (callbackfn: (previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number, initialValue: number): number; (callbackfn: (previousValue: U, currentValue: number, ...' has signatures, but none of those signatures are compatible with each other.(2349)

For further information: my original problem in a project (with the same code and same typescript versions) was that each of the methods above (including a.filter and a.foreach on line 4 and 5) infers its callback’s argument type(s) to be never, thus raising further errors (e.g. Property 'toString' does not exist on type 'never'.ts(2339)). I am not sure why I cannot reproduce that behaviour in a clean installation or in the playground, or vice versa.

Playground Link

Related Issues: #36554 collects various issues around array methods.

Treora added a commit to WebMemex/freeze-dry that referenced this issue May 14, 2020
@RyanCavanaugh RyanCavanaugh added the Design Limitation Constraints of the existing architecture prevent this from being fixed label Jun 5, 2020
@RyanCavanaugh
Copy link
Member

In general we can't resolve calls on union types unless the types involved are very similar, and [] isn't very similar to [number]. You can write ([] & Array<number>) instead of [] in this case to resolve the problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Limitation Constraints of the existing architecture prevent this from being fixed
Projects
None yet
Development

No branches or pull requests

2 participants