Joseph
Joseph

Reputation: 4685

Typescript function using generics and rest properties doesn't automatic collect all possible types

Please see this minimum code below.

function zip<T>(...arrs: T[][]): T[][] {
  return arrs
}

zip([1,2,3], ['a', 'b', 'c'])
// Type 'string' is not assignable to type 'number'.ts(2322)

zip<number | string>([1,2,3], ['a', 'b', 'c'])
// Ok, but a little bit bother to me.

I created a function using generics and rest properties.

When I directly use zip([1,2,3], ['a', 'b', 'c']), I expect that typescript automatically finds out I'm using number | string type, is there any way to achieve this?

enter image description here

Upvotes: 1

Views: 165

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249506

Typescript sees the first parameter is number[] and this fixes T and then you get an error for the second. While in theory T could be inferred to string | number I would argue the current behavior is usually a good thing, it is more likely infering unions would lead to unexpected errors in other places.

You can get the compiler to accept the call you want if you make the compiler consider all the arguments as a whole, not individually, using tuples in rest parameters:

function zip<T extends any[][]>(...arrs: T): (T[number][number])[][] {
    return arrs
}

zip([1,2,3], ['a', 'b', 'c'])

T will be a tuple type for the sample call ([number[], string[]], so to get the item type we use T[number][number] (which will be string | number for the sample call), and the get back to the array of arrays using [][]

Upvotes: 1

Related Questions