X Tutup
The Wayback Machine - https://web.archive.org/web/20210805133540/https://github.com/microsoft/TypeScript/issues/36390
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 · 13 comments

Comments

@IvanKalinin
Copy link

@IvanKalinin IvanKalinin commented Jan 24, 2020

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

@DanielRosenwasser DanielRosenwasser commented Jan 24, 2020

I think this is a duplicate of #7294

@jcalz
Copy link
Contributor

@jcalz 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 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

@dragomirtitian dragomirtitian commented Feb 12, 2020

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

@weswigham weswigham commented Feb 12, 2020

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

@dragomirtitian dragomirtitian commented Feb 12, 2020

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

@weswigham
Copy link
Member

@weswigham 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

@dragomirtitian dragomirtitian commented Feb 12, 2020

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 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 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
});
@aksdevac
Copy link

@aksdevac aksdevac 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 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

@ialexryan ialexryan commented Jun 1, 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

X Tutup