292

I'm creating a class in typescript that has a property that is an ES6 (ECMAscript 2016) Map like so:

class Item {
  configs: ????;
  constructor () {
    this.configs = new Map();
  }
}

How do I declare an ES6 Map type in typescript?

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
nicksrandall
  • 3,008
  • 2
  • 12
  • 9

11 Answers11

373

EDIT (Jun 5 2019): While the idea that "TypeScript supports Map natively" is still true, since version 2.1 TypeScript supports something called Record.

type MyMapLikeType = Record<string, IPerson>;
const peopleA: MyMapLikeType = {
    "a": { name: "joe" },
    "b": { name: "bart" },
};

Unfortunately the first generic parameter (key type) is still not fully respected: even with a string type, something like peopleA[0] (a number) is still valid.


EDIT (Apr 25 2016): The answer below is old and should not be considered the best answer. TypeScript does support Maps "natively" now, so it simply allows ES6 Maps to be used when the output is ES6. For ES5, it does not provide polyfills; you need to embed them yourself.

For more information, refer to mohamed hegazy's answer below for a more modern answer, or even this reddit comment for a short version.


As of 1.5.0 beta, TypeScript does not yet support Maps. It is not yet part of the roadmap, either.

The current best solution is an object with typed key and value (sometimes called a hashmap). For an object with keys of type string, and values of type number:

var arr : { [key:string]:number; } = {};

Some caveats, however:

  1. keys can only be of type string or number
  2. It actually doesn't matter what you use as the key type, since numbers/strings are still accepted interchangeably (only the value is enforced).

With the above example:

// OK:
arr["name"] = 1; // String key is fine
arr[0] = 0; // Number key is fine too

// Not OK:
arr[{ a: "a" }] = 2; // Invalid key
arr[3] = "name"; // Invalid value
Willem Renzema
  • 5,177
  • 1
  • 17
  • 24
zeh
  • 10,130
  • 3
  • 38
  • 56
  • 5
    How then do you iterate the properties in the map? When I do arr.values(), I get "Property 'values' does not exist on type..." – Vern Jensen Sep 02 '15 at 21:59
  • Not the same as `values()`, I'd do `for (var key in arr) ... arr[key]` or [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of). Other solution (which is more and more realistic nowadays and will be for a while for a lot of things) is to use [corejs](https://github.com/Microsoft/TypeScript/issues/3956). – zeh Sep 03 '15 at 22:40
  • In fact when I use any key as a property on a map declared in this way I get "Property 'whatever' does not exist on type" – rakslice Mar 19 '16 at 01:29
  • I'm using the map class to build one, but even if I do `map Map=new Map()` when i do `map.set(something)` I get an exception `map is undefined`, is there another way to initialize it? – mautrok Aug 18 '16 at 08:51
  • 1
    When targetting ES5, even with polyfills, you can't use certain features - see github.com/Microsoft/TypeScript/issues/6842 – Ondra Žižka Dec 14 '16 at 02:51
  • @novaline no. Map-wise there's no update needed as the way it works (with polyfills for ES5) is party of the core design of TS. – zeh Jul 25 '17 at 16:35
  • 1
    The Record type was exactly what I needed to replace Map! I had no idea this existed, thank you!! – Zpeed Tube Mar 04 '21 at 22:12
134

See comment in: https://github.com/Microsoft/TypeScript/issues/3069#issuecomment-99964139

TypeScript does not come with built in pollyfills. it is up to you to decide which pollyfill to use, if any. you can use something like es6Collection, es6-shims, corejs..etc. All the Typescript compiler needs is a declaration for the ES6 constructs you want to use. you can find them all in this lib file.

here is the relevant portion:

interface Map<K, V> {
    clear(): void;
    delete(key: K): boolean;
    entries(): IterableIterator<[K, V]>;
    forEach(callbackfn: (value: V, index: K, map: Map<K, V>) => void, thisArg?: any): void;
    get(key: K): V;
    has(key: K): boolean;
    keys(): IterableIterator<K>;
    set(key: K, value?: V): Map<K, V>;
    size: number;
    values(): IterableIterator<V>;
    [Symbol.iterator]():IterableIterator<[K,V]>;
    [Symbol.toStringTag]: string;
}

interface MapConstructor {
    new <K, V>(): Map<K, V>;
    new <K, V>(iterable: Iterable<[K, V]>): Map<K, V>;
    prototype: Map<any, any>;
}
declare var Map: MapConstructor;
user247702
  • 23,641
  • 15
  • 110
  • 157
mohamed hegazy
  • 9,191
  • 4
  • 30
  • 21
  • 3
    When targetting ES5, even with polyfills, you can't use certain features - see https://github.com/Microsoft/TypeScript/issues/6842 – Ondra Žižka Dec 14 '16 at 02:50
106

Here is an example:

this.configs = new Map<string, string>();
this.configs.set("key", "value");

Demo

Arnaud
  • 7,259
  • 10
  • 50
  • 71
  • 1
    @Zelphir For your error `TS2304`, please check this : https://stackoverflow.com/questions/39416691/webpack-ts2304-cannot-find-name-map-set-promise – Arnaud Sep 29 '17 at 02:28
53

Yes Map is now available in typescript.. if you look in lib.es6.d.ts, you will see the interface:

interface Map<K, V> {
  clear(): void;
  delete(key: K): boolean;
  forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void,thisArg?: any): void;
  get(key: K): V | undefined;
  has(key: K): boolean;
  set(key: K, value: V): this;
  readonly size: number;} 

Its great to use as a dictionary of string,object pairs.. the only annoyance is that if you are using it to assign values elsewhere with Map.get(key) the IDE like Code gives you problems about being possible undefined.. rather than creating a variable with an is-defined check .. simply cast the type (assuming you know for sure the map has the key-value pair)

class myclass {
   mymap:Map<string,object>
   ...
   mymap = new Map<string,object>()
   mymap.set("akey",AnObject)
   let objectref = <AnObject>mymap.get("akey")
nphias
  • 591
  • 4
  • 7
14

How do I declare an ES6 Map type in typescript?

You need to target --module es6. This is misfortunate and you can raise your concern here : https://github.com/Microsoft/TypeScript/issues/2953#issuecomment-98514111

basarat
  • 261,912
  • 58
  • 460
  • 511
12

As a bare minimum:

tsconfig:

 "lib": [
      "es2015"
    ]

and install a polyfill such as https://github.com/zloirock/core-js if you want IE < 11 support: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

Nikos
  • 7,295
  • 7
  • 52
  • 88
10

Not sure if this is official but this worked for me in typescript 2.7.1:

class Item {
   configs: Map<string, string>;
   constructor () {
     this.configs = new Map();
   }
}

In simple Map<keyType, valueType>

Jonas Tomanga
  • 1,069
  • 10
  • 19
4

With the lib config option your are able to cherry pick Map into your project. Just add es2015.collection to your lib section. When you have no lib config add one with the defaults and add es2015.collection.

So when you have target: es5, change tsconfig.json to:

"target": "es5",
"lib": [ "dom", "es5", "scripthost", "es2015.collection" ],
HolgerJeromin
  • 2,201
  • 20
  • 21
2

Typescript does not yet support Map.

ES6 Compatibility Table

Logan Tegman
  • 829
  • 5
  • 9
1

Add "target": "ESNEXT" property to the tsconfig.json file.

{
    "compilerOptions": {
        "target": "ESNEXT" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
    }
}
Yas
  • 4,957
  • 2
  • 41
  • 24
0

You can create a Map inside a Typescript class as follows

export class Shop {
  public locations: Map<number, string>;

  constructor() {
   // initialize an empty map
   this.locations= new Map<number,string>();
  }

   // get & set functions
   ........
}
Lenzman
  • 1,177
  • 18
  • 30