Hit this odd bug in my code and I can’t figure the way to get a constant time lookup from a Map when using a tuple as my key.
Hopefully this illustrates the issue, and the workaround I’m using now just to get it to work:
hello.ts:
let map: Map<[number, number], number> = new Map<[number, number], number>() .set([0, 0], 48); console.log(map.get([0,0])); // prints undefined console.log(map.get(String([0, 0]))); // compiler: error TS2345: Argument of type // 'string' is not assignable to parameter of type '[number, number]'. //the work-around: map.forEach((value: number, key: [number, number]) => { if(String(key) === String([0, 0])){ console.log(value); // prints 48 } })
To compile (transpile?) I’m using:
tsc hello.ts -target es6
tsc version 2.1.6
Tried several things to make the Map.get() method to work, not having much success.
Advertisement
Answer
In JavaScript (and as an extension, TypeScript), no two arrays are equal except if they refer to the same array (i.e., when changing the elements of one also would change the elements of another). If you create a new array with the same elements, it would not consider it to be equal to any existing one.
Because Maps consider such equality when looking up elements, if you store a value with an array as a key, you can only get the value out again if you pass in the exact same array reference as a key again:
const map: Map<[ number, number], number> = new Map<[ number, number ], number>(); const a: [ number, number ] = [ 0, 0 ]; const b: [ number, number ] = [ 0, 0 ]; // a and b have the same value, but refer to different arrays so are not equal a === b; // = false map.set(a, 123); map.get(a); // = 123 map.get(b); // = undefined
One simple workaround for this is to use strings or numbers as keys, as these are always considered equal when they have the same value:
const map: Map<string, number> = new Map<string, number>(); const a: [ number, number ] = [ 0, 0 ]; const b: [ number, number ] = [ 0, 0 ]; const astr: string = a.join(','); // = '0,0' const bstr: string = b.join(','); // = '0,0' // astr and bstr have the same value, and are strings so they are always equal astr === bstr; // = true map.set(astr, 123); map.get(astr); // = 123 map.get(bstr); // = 123