How to map a typescript tuple into a new tuple using Array.map

Viewed 724

I tried mapping a TypeScript Tuple into another Tuple using Array.map like so:

const tuple1: [number, number, number] = [1, 2, 3];
const tuple2: [number, number, number] = tuple1.map(x => x * 2);
console.log(tuple2);

TypeScript Playground Example

But the typescript compiler is telling me this is not possible:

Type 'number[]' is not assignable to type '[number, number, number]'.
Target requires 3 element(s) but source may have fewer.

Is there a clean way to map a tuple into a new tuple without using Array.map or a way to use Array.map that the compiler does understand?

1 Answers

TypeScript currently lacks suitable tuple method overload definitions for map inside Array.

You can globally augment the Array type declaration like this:

// important: put Array augmentation in a script/non-module file without import/export
interface Array<T> {
    // T[] | [T] enforces a tuple type.
    // {[K in keyof this]: U} keeps a mapped tuple type.
    map<U>(callbackfn: (value: T, index: number, tuple: T[] | [T]) => U, thisArg?: any): {[K in keyof this]: U}
}
const t1: [number, number] = [1, 2];
const t1M = t1.map(x => x * 2); // t1M: [number, number]
const t2: [number, number, number] = [1, 2, 3];
const t2M = t2.map(String); // t2M: [string, string, string]

const t3: number[] = [1, 2, 3]
const t3M = t3.map(x => x * 2); // t3M: number[]

Live code playground

Update: If T[] | [T] looks too weird, you can also use variadic tuple notation (TS 4.0):

callbackfn: (value: T, index: number, tuple: [...this]) => U

Live code playground

Related