Skip to content

mapping over an array of tuple types does not give the correct type #11312

Closed

Description

@mattyork

TypeScript Version: 2.0.3

Code

The map callback in the code below is the identity function.

let arr: Array<[number, number]> = [[1, 2]]

let mappedArr: Array<[number, number]> = arr.map(([x, y]) => {
    return [x, y];
})

Expected behavior: mappedArr is of type Array<[number, number]>. Compilation works.

Actual behavior: Doesn't work. Error message:

Type 'number[][]' is not assignable to type '[number, number][]'.
  Type 'number[]' is not assignable to type '[number, number]'.
    Property '0' is missing in type 'number[]'.

TypeScript playground link

Activity

  1. kitsonk commented on Oct 3, 2016

    @kitsonk
    Contributor

    Tuples are never inferred. On the return, you have to be explicit:

    let arr: Array<[number, number]> = [[1, 2]]
    
    let mappedArr: Array<[number, number]> = arr.map(([x, y]) => {
        return <[number, number]> [x, y];
    });

    ... or ...

    let arr: Array<[number, number]> = [[1, 2]]
    
    let mappedArr: Array<[number, number]> = arr.map(([x, y]): [number, number] => {
        return [x, y];
    });

    But of course then you don't have to be explicit about the left hand side then:

    let arr: Array<[number, number]> = [[1, 2]]
    
    let mappedArr = arr.map(([x, y]): [number, number] => {
        return [x, y];
    });
  2. gcnew commented on Oct 3, 2016

    @gcnew
    Contributor

    You can also manually augment map as proposed in #11252.

  3. kitsonk commented on Oct 3, 2016

    @kitsonk
    Contributor

    Which means this is dupe of #6574, I had forgotten.

  4. calebegg commented on Oct 28, 2016

    @calebegg

    I don't think this is a dupe; that issue is about mapping tuples to tuples (and also, it's fixed). This is about mapping arrays of tuples to arrays of tuples.

    The issue could be more succinctly stated as: "Tuple return types are not inferred". Here's a simple repro case:

    http://www.typescriptlang.org/play/#src=function%20foo(x%3A%20number%2C%20y%3A%20string)%20%7B%0D%0A%20%20%20%20return%20%5Bx%2C%20y%5D%3B%0D%0A%7D

    (note that the return type is (number | string)[] instead of [number, string])

    The fact that arrow functions therefore can't map tuples to tuples is just a consequence of that.

  5. mhegazy commented on Oct 29, 2016

    @mhegazy
    Contributor

    This is another manifestation of #11152.

    map is declared as:

    map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];

    so you see U is only inferred from the return type of the callback function. since tuple types are never inferred unless there is a contextual type (which in this case there is none), a regular array type is inferred for U, then the assignment check is done, and it fails.

    The piece that is missed here, is we know that the U[] will be assigned to mappedArr, and we should use this as a contextual type. #11152 tracks propagating using the return type of the contextual signature if one exists as another location for inference.

  6. locked and limited conversation to collaborators on Jun 19, 2018
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

    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