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

.map() .reduce() .filter() methods fail with "This expression is not callable." error on valid array with union type #36390

Closed
IvanKalinin opened this issue Jan 24, 2020 · 21 comments · Fixed by #31023
Assignees
Labels
Experience Enhancement Noncontroversial enhancements Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone Suggestion An idea for TypeScript

Comments

@IvanKalinin
Copy link

TypeScript Version: any

Code:

const arr: number[] | string[] = [];  // Works with Array<number | string>
const arr1: number[]  = [];
const arr2:  string[] = [];

arr.map((a: number | string, index: number) => { 
    return index
})

arr.reduce((acc: Array<string>, a: number | string, index: number) => { 
    return []
}, [])

arr.forEach((a: number | string, index: number) => { 
    return index
})

arr1.map((a: number, index: number) => { 
    return index
})

arr1.reduce((acc: number[], a: number, index: number) => { 
    return [a]
}, [])

arr1.forEach((a: number, index: number) => { 
    return index
})
arr2.map((a:  string, index: number) => { 
    return index
})

arr2.reduce((acc: string[], a: string, index: number) => { 
    return []
}, [])

arr2.forEach((a: string, index: number) => { 
    return index
})

Expected behavior: TS should let me iterate through array (I tell it the type is either array of numbers OR array of strings (not an array of mixed types). In any case the variable is an array and those methods should be callable.

Actual behavior: TS throws error "This expression is not callable."

@IvanKalinin IvanKalinin changed the title Union type of arrays fails on .map() .reduce() .filter() methods with "This expression is not callable." .map() .reduce() .filter() methods fail with "This expression is not callable." error on valid array with union type Jan 24, 2020
@DanielRosenwasser
Copy link
Member

I think this is a duplicate of #7294

@jcalz
Copy link
Contributor

jcalz commented Jan 24, 2020

Duplicate of #7294 (see comment). Related to #29011.

Mentioned in documentation as caveats for improved behavior for calling union types:

This new behavior only kicks in when at most one type in the union has multiple overloads, and at most one type in the union has a generic signature. That means methods on number[] | string[] like map (which is generic) still won’t be callable.

@jcjolley
Copy link

jcjolley commented Feb 12, 2020

Is this really a duplicate? The 'duplicate' issue is marked as closed, but this issue still exists. If it really is a duplicate, can we re-open #7294 to handle this case?

@dragomirtitian
Copy link
Contributor

The reason stated by @weswigham for not unifying for generic signatures with multiple signatures is that:

Well, it's because we don't really know if the generics are the same (and so because of that we'd opt to make the parameter type T & T' instead and combine the type parameter lists to <T, T'>), so we opt to not allow the call.

But for function signatures originating from the same declaration we can be sure that we are talking about the same overload signatures in the same order and with the same generic parameters. As long as the generics don't have constraints, unifying the signatures should be safe IMO.

I think that unifying for this case would satisfy a lot of use cases. Array and Promise would benefit from this and those are the usual place people run into this limitation.

@weswigham
Copy link
Member

Yeah, I have a change around here somewhere that allows it for exactly that situation rummages through bin of old PRs

@dragomirtitian
Copy link
Contributor

@weswigham What was wrong with it? Why did it get stuck ? Can we revive it :D ?

@weswigham
Copy link
Member

weswigham commented Feb 12, 2020

#31023 contains the relevant code. It's a bit old, and some parts of it are probably no longer needed thanks to some other signature resolution changes we made (namely the base signature stuff should no longer be needed).

@dragomirtitian
Copy link
Contributor

Cool! So is this planned for a release in the future I'm guessing? I wanted to have a look at this over the weekend but glad to see it already there and we will get eventually :)

@eritbh
Copy link

eritbh commented Feb 26, 2020

Looks like my issue #36307 talks about pretty much the same behavior, linking for discoverability. Glad to see there's been some movement!

@sazzy4o
Copy link

sazzy4o commented Jun 10, 2020

Until this gets fix you can do something like:

const arr: number[] | string[] = [];
// Add as any[]
(arr as any[]).map((a: number | string, index: number) => { 
    return index
});

@imaksp
Copy link

imaksp commented Jul 6, 2020

I got similar error while calling map on Dictionary<CustomType[]>, hope this gets fixed soon, currently used lodash-es's map to avoid this.

@jcalz
Copy link
Contributor

jcalz commented May 12, 2021

This issue is closed, but the reduce() example persists:

const arr: number[] | string[] = [];

arr.reduce((acc: Array<string>, a: number | string, index: number) => {
  return []
}, [])

/* This expression is not callable.
  Each member of the union type '...' has signatures,
  but none of those signatures are compatible with each other. */

Playground link

@ialexryan
Copy link
Contributor

I'm super excited about the improvements in #31023! But it doesn't seem to have completely resolved the issues with calling array methods on unions of arrays.

I tested a few common array methods and found the following results:

I've created a new issue to track the remaining functionality.

@Wharley01
Copy link

is this getting fixed anytime soon ?

@zoeytruong
Copy link

zoeytruong commented Nov 17, 2021

I'm super excited about the improvements in #31023! But it doesn't seem to have completely resolved the issues with calling array methods on unions of arrays.

I tested a few common array methods and found the following results:

I've created a new issue to track the remaining functionality.

@ialexryan What typescript version does this fix go out?

rkostyuchenko added a commit to Studio-Yandex-Practicum/lubimovka_frontend that referenced this issue Nov 22, 2021
rkostyuchenko added a commit to Studio-Yandex-Practicum/lubimovka_frontend that referenced this issue Nov 22, 2021
rkostyuchenko added a commit to Studio-Yandex-Practicum/lubimovka_frontend that referenced this issue Nov 22, 2021
@shamilovtim
Copy link

shamilovtim commented Dec 29, 2021

We're on the latest Typescript and bumped into this. Do you know when it's going out? @RyanCavanaugh

@ivan-oj
Copy link

ivan-oj commented Jan 21, 2022

I just bumped into the same issue

@mikkelwf
Copy link

How is this issue closed?
.filter() and .find() is still not working as of 4.9.5..

@jcalz
Copy link
Contributor

jcalz commented Feb 11, 2023

I think #44373 is the open issue about this

@mikkelwf
Copy link

Thanks, didn't see that.. :)

@khaledtb
Copy link

I just bumped into the same issue too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Experience Enhancement Noncontroversial enhancements Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.