Skip to content

Potential regression in 4.2 - Calling .map on T[] | Y[] is now callable but leads to an implicit any errorΒ #42646

Description

Bug Report

πŸ”Ž Search Terms

expression not callable union arrays

πŸ•— Version & Regression Information

This changed between versions 4.1.3 and 4.2 beta

⏯ Playground Link

https://www.typescriptlang.org/play?ts=4.1.3#code/CYUwxgNghgTiAEYD2A7AzgF3gDwFzxQFcBbAIxBgG0BdeAH3kxgEsUBzGgKE+wDpioABwAUAM3gBeAHzxRASiA

https://www.typescriptlang.org/play?ts=4.2.0-beta#code/CYUwxgNghgTiAEYD2A7AzgF3gDwFzxQFcBbAIxBgG0BdeAH3kxgEsUBzGgKE+wDpioABwAUAM3gBeAHzxRASiA

πŸ’» Code

declare const x: number[] | string[]

x.map(f => f)

πŸ™ Actual behavior

.map is now callable but f as an implicit type of any, leading to an implicit any error.

πŸ™‚ Expected behavior

The current behaviour in 4.1.3 is to mark the map() call as not callable as well as f should have an implicit any type.

I don't know if this is a regression but I'm raising it because this change in behaviour is not documented in the release notes.

Activity

  1. changed the title [-]Potential regression in 4.2 - Calling `.map` on `T[] | Y[]` is now callback but leads to an implicit any error[/-] [+]Potential regression in 4.2 - Calling `.map` on `T[] | Y[]` is now callable but leads to an implicit any error[/+] on Feb 4, 2021
  2. weswigham commented on Feb 4, 2021

    @weswigham
    Member

    It's not a regression (definitionally, going from can't call at all to implicitly any is a less restrictive error - now you can explicitly annotate it and actually resolve the call), and we already have #42620 open to improve the experience further~

  3. thorn0 commented on Feb 4, 2021

    @thorn0

    But why does it allow specifically map (and some)? every and filter are still errors.

    related issue: #35045

  4. weswigham commented on Feb 4, 2021

    @weswigham
    Member

    every and filter have multiple overloads (with differing numbers of type parameters) which makes the union call difficult to resolve, while map only has one overload, so combining the signatures is much more straightforward.

  5. thorn0 commented on Feb 4, 2021

    @thorn0

    Is there any chance for every to work for unions of read-only array types in the foreseeable future?

  6. weswigham commented on Feb 4, 2021

    @weswigham
    Member

    Not in the immediate future, no. The readonly-ness isn't what matters for our ability to check it - the overload count/genericness of the signature is. We've been slowly expanding how much of that we can check, but I can't make any claims as to how far we'll go or by when.

  7. thorn0 commented on Feb 4, 2021

    @thorn0

    I see, thanks. For some reason, I thought these methods are disallowed because of type safety. E.g., what can be pushed to an array if it's type is string[] | number[]? So it looked like readonly-ness might help. But now I see I misunderstood the problem.

  8. thorn0 commented on Feb 4, 2021

    @thorn0

    Anyway, wouldn't it be a helpful trick to implicitly transform readonly string[] | readonly number[] to readonly (string | number)[] for the purposes of signature merging?

  9. tom-sherman commented on Feb 4, 2021

    @tom-sherman
    Author

    [...] and we already have #42620 open to improve the experience further~

    Wesley Wigham (@weswigham) It's not clear to me how your PR relates to this issue, do you have a playground link I can poke around with?

  10. thorn0 commented on Feb 4, 2021

    @thorn0

    Tom Sherman (@tom-sherman) Previously, such calls were disallowed because merging signatures for generic overloaded functions is a tricky procedure, and it wasn't implemented. Now, in some cases, it became possible. After merging that PR, it'll be possible in more cases. Hopefully, we'll read more on that in the release blog post.

  11. thorn0 commented on Aug 26, 2022

    @thorn0

    Now that it works for map, I wonder if this issue should be renamed with a mention of filter and every in the title, That'd make it more discoverable.

  12. thorn0 commented on Aug 26, 2022

    @thorn0

    An isolated real-world case to demo how this issue is a pain:
    playground

    import * as Babel from "@babel/types";
    import { TSESTree } from "@typescript-eslint/typescript-estree";
    type Node = Babel.Node | TSESTree.Node;
    
    declare const node: Node;
    
    if (
        (node.type === "GenericTypeAnnotation" || node.type === "TSTypeReference") &&
        (!node.typeParameters ||
            node.typeParameters.params.length <= 2 && node.typeParameters.params.every(n => true))
    ) { }

    every causes the following error:

    This expression is not callable.
      Each member of the union type '{ <S extends TSType>(predicate: (value: TSType, index: number, array: TSType[]) => value is S, thisArg?: any): this is S[]; (predicate: (value: TSType, index: number, array: TSType[]) => unknown, thisArg?: any): boolean; <S extends TSType>(predicate: (value: TSType, index: number, array: TSType[]) => value is S, thi...' has signatures, but none of those signatures are compatible with each other.(2349)
    
  13. jakebailey commented on Jun 20, 2023

    @jakebailey
    Member

    Closing as fixed in #53489; reading the PR, it has this case as a test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions