4

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?

Mathijs
  • 477
  • 1
  • 5
  • 13
  • `tuple1.map(x => x * 2) as [number, number, number];`, but that's not ideal I guess? :) – Nsevens Dec 17 '20 at 07:04
  • Discovered that one already indeed. But that's cheating the compiler ;-) – Mathijs Dec 17 '20 at 07:06
  • Take a look at how it's done in `fp-ts`. There's a Tuple module where you can do `const z: [number,number,number] = pipe(x, tuple.map(x => x*2))` with no problems. Or `const z: [number,number,number] = tuple.map(x => x*2)(x)` It's probably done with declare function overloads. – user1713450 Dec 17 '20 at 07:12
  • Interesting, will have a look at fp-ts @user1713450 ! – Mathijs Dec 17 '20 at 07:29

1 Answers1

2

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

A_blop
  • 792
  • 2
  • 11