Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript error with zip function in Lodash

I was wondering why Typescript complains with the following error:

(22,28): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
  Type argument candidate 'string' is not a valid type argument because it is not a supertype of candidate 'number[]'.

when I use the zip function with the following arguments:

let ranges = ["0-100", "100-200", "200-300", "300-400", "400-500"];
let arrays = [[19.99, 49.99, 49.99, 49.99, 29.99, 29.99, 9.99, 29.99, 34.99, 34.99, 59.99], [149.99, 179.99, 129.99, 149.99, 129.99, 199.99, 129.99], [209.99, 249.99, 292.99, 279.99, 219.99]];

let result = _.zip(ranges, arrays);

However, if I use _.zipObject, the error disappears.

In case it is important, I installed the type information using typings install lodash --save.

UPDATE 2

I think zip doesn't like to receive arguments with different types. In this case, ranges is of type string[] and arrays of type number[].

UPDATE

I was wrong. I changed the values of arrays to use strings, but now I get this slightly different error:

(24,28): error TS2453: The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly.
  Type argument candidate 'string' is not a valid type argument because it is not a supertype of candidate 'string[]'.

Maybe there is something related to the nested arrays in the variable arrays?

like image 690
Robert Smith Avatar asked Sep 13 '25 09:09

Robert Smith


2 Answers

You are correct that zip does not like arguments of different types. As defined here...

zip<T>(...arrays: List<T>[]): T[][];

This basically means that all of the parameters must be an array of the same type. However, when you changed arrays to strings I suspect you had something like...

let ranges = ["0-100", "100-200", "200-300", "300-400", "400-500"];
let arrays = [["19.99", "49.99",...], ["149.99", ...], ...];

These are still not the same type. ranges is a one dimensional array of strings (array of string) and arrays is a two dimensional array of strings (array of string[]). A valid set of inputs would be something like...

let ranges = ["0-100", "100-200"];
let arrays = ["19.99", "49.99"];

Here both types are arrays of strings. However, I suspect this is not what you want. Is your desired output something like the following?

[["0-100", ["19.99", ...]], ["100-200", ["149.99", ...]], ...]

If so then you can simply do...

_.zip<any>(ranges, arrays);

This tells typescript to force T to be any so the function definition becomes...

zip(...arrays: List<any>[]): any[][];

Example:

let ranges = ["0-100", "101-200"];
let arrays = [[0, 1, 2], [3, 4, 5]];
_.zip<any>(ranges, arrays);
//[ [ '0-100', [ 0, 1, 2 ] ], [ '101-200', [ 3, 4, 5 ] ] ]

UPDATE: As mentioned in the comments, you could also do...

_.zip<string|number[]>(ranges, arrays);
like image 149
Pace Avatar answered Sep 16 '25 02:09

Pace


There is now a form of _.zip which allows you to specify, as type parameters, the types contained within the arrays.

zip<T1, T2>(arrays1: List<T1>, arrays2: List<T2>): Array<[T1 | undefined, T2 | undefined]>;

so you would be able to write

_.zip<string, number[]>(ranges, arrays);

This would return Array<[string | undefined, number[] | undefined]> and would allow you to avoid using any (which defeats the purpose of using TypeScript)

like image 45
randbw Avatar answered Sep 16 '25 02:09

randbw