2

This is what i personally would consider correct in various languages, but here it is not. I must be ignorant of an aspect of Typescript, but I can not so easy determine where the gap is.

The implementation requires a map of maps. The top map is a string key, and the a map of string-keys and string-values.

class aClass
{
    myMap: Map<string, Map<string, string>>;

    constructor ()
    {
        this.myMap = new Map<string, Map<string, string>>([
            ["key1", new Map<string,string>()],
            ["key2", new Map<string,string>()]
        ]);
    }

    async aTask(map: Map<string,string>)
    {
        map.set("subKey1", "VALUE");
    }

    async someWork()
    {
        this.aTask(this.myMap["key1"]);
        this.aTask(this.myMap.get("key1"));
    }
}

How do I correctly access the Map<string, string>() in the function someWork() ?

The error for the first accessor : this.aTask(this.myMap["key1"]);

Element implicitly has an 'any' type because type 'Map<string, Map<string, string>>' has no index signature. Did you mean to call 'get'?

The error for the second accessor : this.aTask(this.myMap.get("key1"));

Argument of type 'Map<string, string> | undefined' is not assignable to parameter of type 'Map<string, string>'. Type 'undefined' is not assignable to type 'Map<string, string>'.

4
  • When I have a question about JavaScript, my first stop is MDN, which has great docs on Map. Commented Oct 20, 2020 at 0:52
  • @HereticMonkey I do indeed read those docs, but this it turns out is a bit of EBNF that needs unpicking to make sense of the error. Commented Oct 20, 2020 at 1:01
  • To be fair, there was no TypeScript error in the question when I made that comment. Commented Oct 20, 2020 at 1:05
  • Have you tried to do what the error message tells you to do? Commented Oct 20, 2020 at 6:14

1 Answer 1

2

Maps, despite being objects, don't put their values onto properties of the Map instance, which is why this.myMap["key1"] doesn't work.

TypeScript doesn't let you do

this.aTask(this.myMap.get("key1"));

because the .get does not guarantee that the key exists in the Map; it's warning you that it might have returned undefined. To be type-safe, do:

async someWork() {
    const val = this.myMap.get("key1");
    if (val) {
        this.aTask(val);
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

is this identified with 'Map<string, string> | undefined' whereby the internal definition includes the option to allow the 'undefined' type, whereas this is not allowed in the call ?
Yes - .get's type definition is: interface Map<K, V> { get(key: K): V | undefined;. It requires you to validate that the value actually exists in the Map first. Eg, if you did this.aTask(this.myMap.get("foobar")); that would throw a runtime error because the key doesn't exist, so TS is forcing you to validate it first.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.