Skip to content

Still only the last overloaded signature is picked when passing an overloaded function to Array.mapΒ #61398

Closed as duplicate of#47571
@ExplodingCabbage

Description

@ExplodingCabbage

πŸ”Ž Search Terms

map overload overloaded

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about overloading

⏯ Playground Link

https://www.typescriptlang.org/play/?noImplicitAny=false#code/GYVwdgxgLglg9mABMOcAUAPAXIsIC2ARgKYBOAlDnkWQNwBQoksCyqmOAzlKTGAOaVE3XgIZNo8JCnQZyiAN71EKxKWJQQpJBgYBfevQgJuiAIalSVAiVIBtALqIAvIjsBGADQAmTwGYHADp8MwAHNBlyWiA

Bug report

This code fails to compile:

function foo(x: number): number;
function foo(x: string): string;
function foo(x) {
    return x;
}

const arr: number[] = [1,2,3].map(foo);

with the following errors:

Type 'string[]' is not assignable to type 'number[]'.
  Type 'string' is not assignable to type 'number'.

and

Argument of type '{ (x: number): number; (x: string): string; }' is not assignable to parameter of type '(value: number, index: number, array: number[]) => string'.
  Type 'number' is not assignable to type 'string'.

This doesn't make much sense, since there's no reason (so far as I can see) that TypeScript shouldn't be able to recognise that foo will only be passed numbers as arguments when called via [1,2,3].map(foo);, and that therefore (per the two overload signatures) will only return numbers, not strings. Furthermore, it can in fact infer this if you use an arrow function instead of passing foo as an argument directly, i.e. this compiles just fine:

function foo(x: number): number;
function foo(x: string): string;
function foo(x) {
    return x;
}

const arr: number[] = [1,2,3].map(x => foo(x));

Especially odd is that the original code also compiles fine if you swap the order in which the overloads are defined:

function foo(x: string): string;
function foo(x: number): number;
function foo(x) {
    return x;
}

const arr: number[] = [1,2,3].map(foo);

The explanation appears to me to be that posited by #55840 - that, when an overloaded function is passed as a parameter to a function like Array.map, TypeScript simply (and arbitrarily, and incorrectly) treats its final overload signature as the signature of the function. It should instead infer from context which overload signature is applicable, as it successfully does if you wrap the call in an arrow function.

#55840 was closed as a dupe of #47571, which was closed as having been completed, and indeed the specific example given in that issue no longer seems to reproduce the bug (so I guess that something got changed to fix at least that case), but the underlying bug doesn't seem to have truly been fixed since the trivial example I give at the start of this issue still reproduces it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    DuplicateAn existing issue was already created

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions