Search code examples
javascripttypescripttypestype-conversiontypeerror

returning an Array of tuples using map on an Array in Typescript


I have an Array const x:number[] = [1,2,3,4,5] and I'm trying to obtain an array of tuples containing the original value in x and a value obtained by mapping a function on it.
My attempt was something like this

pos = x.map(xi => (
    [xi, 3*xi]
))

This returns pos as of type number[][] but I want a [number, number] as result.
Do you know how to fix this code?


Solution

  • By default, TypeScript will see an array literal like [xi, 3 * xi] and infer its type to be an unordered array type of arbitrary length like number[], and not a tuple type like [number, number]. That's often what people want, since arrays are more common than tuples. When such inference isn't suitable, you'll need to do something to ask the compiler to do something else.

    There are a number of ways to do this. If you explicitly want [number, number], then the most straightforward approach is to manually specify the U type argument for the Array.prototype.map method which is declared like:

    interface Array<T> {
        map<U>(cb: (v: T, i: number, a: T[]) => U, thisArg?: any): U[];
    }
    

    Like this:

    const x: number[] = [1, 2, 3, 4, 5];
    const pos = x.map<[number, number]>(xi => (
       [xi, 3 * xi]
    ));
    // const pos: [number, number][]
    

    But in general, you can either manually annotate the variable to which you're assigning the literal:

    const pos = x.map(xi => {
       const ret: [number, number] = [xi, 3 * xi];
       return ret;
    });
    // const pos: [number, number][]
    

    or you could use a const assertion to get the compiler to change its inference algorithm to prefer literal types and readonly tuples:

    const pos = x.map(xi => [xi, 3 * xi] as const);
    // const pos: (readonly [number, number])[]
    

    The type readonly [number, number] is not identical to [number, number], but depending on your use case it might suffice.

    Playground link to code