0

I try to declare a recursive type with following interface

interface Map<T> {
  [key: string]: Map<T> | T;
}

However, when I try to get property of this object:

const map: Map<number> = {
  a: {
    b: {
      c: 2
    }
  }
};

console.log(map.a.b.c);

I get an error:

TS2339:Property 'b' does not exist on type 'number | Map<number>'.  Property 'b' does not exist on type 'number'.

I understand why it happens, but is there a workaround?

P.S. My tsconfig.json is following:

{
  "compilerOptions": {
    "declaration": true,
    "downlevelIteration": true,
    "importHelpers": true,
    "lib": [
      "dom",
      "es2017"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "noFallthroughCasesInSwitch": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "sourceMap": true,
    "strict": true,
    "target": "es5",
    "typeRoots": [
      "node_modules/@types"
    ]
  }
}
1

1 Answer 1

2

An indexable type isn't aware of what keys it has, so you cannot use the dot notation, instead, you'll need to use:

console.log(map["a"]["b"]["c"]);

Notice however that the type for map["a"]["b"] is any, you'll need to use (map["a"] as MyMap<number>)["b"] to get the right type.

You shouldn't be using the name Map for your interface because there's now a built-in type called Map (type definition).

If the example you posted really shows your use case then I suggest that you don't annotate the map variable at all:

const map = {
    a: {
        b: {
            c: 2
        }
    }
};
console.log(map.a.b.c); // this is fine now

The compiler is smart enough to infer the type of map to:

type map = {
    a: {
        b: {
            c: number;
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.