Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript error compiling Map

Tags:

typescript

let a : any;
let m = new Map<any, any>(Object.keys(a).map(prop => ([prop.x, prop.y])));

with esnext target produces the error

file: 'file:///c%3A/GIT/MainLine/members/src/tasks/list/decTest2.ts' severity: 'Error' message: 'Argument of type 'any[][]' is not assignable to parameter of type 'Iterable<[any, any]>'. Types of property '[Symbol.iterator]' are incompatible. Type '() => IterableIterator' is not assignable to type '() => Iterator<[any, any]>'. Type 'IterableIterator' is not assignable to type 'Iterator<[any, any]>'. Types of property 'next' are incompatible. Type '(value?: any) => IteratorResult' is not assignable to type '(value?: any) => IteratorResult<[any, any]>'. Type 'IteratorResult' is not assignable to type 'IteratorResult<[any, any]>'. Type 'any[]' is not assignable to type '[any, any]'. Property '0' is missing in type 'any[]'.' at: '4,27' source: 'ts'

which is strange because

let m2 = new Map<any, any>([[1, 2], [2, 3], ['a', 'b']])

compiles fine. What do I need to add to the first sample to get it to compile?

Note that I do know that

let m2 = new Map<any, any>(<any>[[1, 2], [2, 3], ["a", 'b']])

will also fix it, but I'd like to understand why this errors out, and see if there's a more decent fix.

like image 784
Adam Rackis Avatar asked May 25 '17 13:05

Adam Rackis


People also ask

What is sourcemap in typescript?

TSConfig sourceMap. Enables the generation of sourcemap files. These files allow debuggers and other tools to display the original TypeScript source code when actually working with the emitted JavaScript files. Source map files are emitted as .js.map ...

What is the correct configuration for path mapping in typescript?

The mapping in "paths" is resolved relative to "baseUrl". Hence, our configuration should be as follows: When we use this configuration, TypeScript compiler “jumps” up a directory from the src directory and locates the node_modules directory.

How to transpile TypeScript into JavaScript?

Transpile TypeScript into JavaScript #. Step 1: Create a simple TS file #. Open VS Code on an empty folder and create a helloworld.ts file, place the following code in that file... Step 2: Run the TypeScript build #. Step 3: Make the TypeScript Build the default #. Step 4: Reviewing build issues #. ...

How to empty an entire map in typescript?

We can empty an entire Map by using the clear method in typescript map. We use the for-of looping operator to loop over entries in a Map in typescript. The keys method returns the keys in the map as an array which we can loop over using for-of like so.


3 Answers

The problem is that TypeScript doesn't know for sure if your array is meant to be a tuple or a plain array in that context. Type argument inference tries to only use its arguments as inference sites.

As a result, when calling map, it doesn't draw an inference from the type of the parameter of new Map<any, any>(...)) to the return type of map.

TypeScript 2.4 is making some changes in this direction, and your specific scenario was brought up. Discussion and progress on the issue itself can be tracked here.

As a workaround, you can write an explicit return type

(prop): [any, any] => [prop.x, prop.y]

or you can give map an explicit type argument

Object.keys(a).map<[any, any]>(...)

Note that in either case, TypeScript catches the error that x and y are not valid properties on strings.

like image 200
Daniel Rosenwasser Avatar answered Sep 29 '22 09:09

Daniel Rosenwasser


The key here is the type of what your map callback function is returning.

prop => [prop.x, prop.y]

TypeScript doesn't automatically infer tuple types from array literals like the array you're returning—it'll instead assume a regular array type (in this case, any[]) which means your call to map will return an array of that type (in this case, any[][]).

The Map object constructor, however, is expecting an array of a specific tuple type. In this instance, it'll be looking for an array or iterable of [any, any] (we'll call that [any, any][] for simplicity).

Since TypeScript doesn't automatically infer the tuple type from the array you're creating in map, the quickest way to satisfy the typechecker is to specify the return value of the function to show that you intend it to be used as a tuple:

(prop): [any, any] => [prop.x, prop.y]

With the callback's return value type being explicitly set, map will return a value of type [any, any][] which satisfies the Map constructor.

like image 26
Adam Maras Avatar answered Sep 29 '22 09:09

Adam Maras


From the looks of it the compiler simply cannot infer the expected type for map<U> if you set it explicitly, its fine:

let a: any;
let b = Object.keys(a).map<[any, any]>(key => [key, a[key]]);    
let m = new Map<any, any>(b);

the problem is that it is giving up and returning any[][] which is invalid for the expected type tuple: [any, any][]

like image 33
Meirion Hughes Avatar answered Sep 29 '22 09:09

Meirion Hughes