2

I am trying to declare a simple map structure in TypeScript with string keys and some object as a value. Looking at several StackOverflow answers, this is what I came up with:

class Person {
    id: number;
    name: string;
}

interface PersonMap {
    [id: string]: Person;
}

When I try to use this declaration, TypeScript is interpreting PersonMap as an array and not as a map, for example I am not able to get keys or values from the map:

let personMap = {} as PersonMap;

personMap[1] = {
    id: 1,
    name: 'John',
}

let people = personMap.values();

TypeScript complains about the last statement above:

Property 'values' does not exist on type 'PersonMap'

What is the best way to declare a Map in TypeScript?

P.S. It does not look like TypeScript has the ES6 Map type built in. In any case, I would like to create my own Map, not an ES6 map.

Naresh
  • 23,937
  • 33
  • 132
  • 204
  • Are you confused about how to write the `values` method or are you wondering if there is a way to get a `values` method without writing one (without using an ES6 `Map`)? – Sean Vieira May 20 '16 at 10:51
  • Without writing a values method- after all it's a plain old object. So the question is more about how to declare the object for correct type checking. – Naresh May 20 '16 at 10:55
  • 3
    You can't get a `values` method on a type that doesn't have one unless you extend `Object.prototype` - would you consider using `Object.keys(yourMap).map(key => yourMap[key])` an acceptable alternative? – Sean Vieira May 20 '16 at 10:58
  • 1
    Nah, the intent was to constrain the property values of the PersonMap object to be of type Person. If that cannot be easily done in TypeScript, I would rather keep it simple and declare personMap as `any`, like this: `let personMap: any = {}` and be done! – Naresh May 20 '16 at 11:18
  • You've done that with your declarations [as it currently stands](https://www.typescriptlang.org/play/#src=class%20Person%20%7B%0D%0A%20%20%20%20id%3A%20number%3B%0D%0A%20%20%20%20name%3A%20string%3B%0D%0A%7D%0D%0A%0D%0Ainterface%20PersonMap%20%7B%0D%0A%20%20%20%20%5Bid%3A%20string%5D%3A%20Person%3B%0D%0A%7D%0D%0A%0D%0Alet%20personMap%20%3D%20%7B%7D%20as%20PersonMap%3B%0D%0A%0D%0ApersonMap%5B1%5D%20%3D%20%7B%0D%0A%20%20%20%20id%3A%201%2C%0D%0A%20%20%20%20name%3A%20'John'%2C%0D%0A%7D%0D%0A%0D%0ApersonMap%5B'not-a-person'%5D%20%3D%20%7Bx%3A%201%2C%20y%3A%202%7D) – Sean Vieira May 20 '16 at 11:31
  • (Notice the type error on the last line). – Sean Vieira May 20 '16 at 11:31
  • Yeah, I noticed that. However, even with that approach, I can't do `personMap.values()` - which is important to me because I want to be able to extract `Person` objects from the map, e.g. to create an array of people sorted by their name. – Naresh May 20 '16 at 11:38
  • Yep, I think it's very similar. If you put a summary down as the answer, I will mark it as correct. – Naresh May 20 '16 at 11:53
  • Linked duplicate doesn't answer the OPs question. To use `values` it needs to be a Map type, which is supported in ES6+. So if your environment has Map support (validate, use shim if not), then you can do this: `interface IPerson { id: number; name: string; } let personMap = new Map(); personMap.set(1, { id: 1, name: 'John' }); let people = personMap.values(); console.log(people);` – radicand Aug 08 '18 at 15:49
  • You can get the values using `Object.values(people)`. That's the best and normal way. – AskYous Aug 08 '18 at 22:37

1 Answers1

4

Have you tried the Map object?

let personMap = new Map()

map.set("1234", person1)
map.set("4567", person2)

map.get("1234")   =>  person1

In-line declaration:

export const Person Map = new Map([
  ["1234", person1],
  ["5678", person2]
])
Lars
  • 9,976
  • 4
  • 34
  • 40