Map<K, V>, Set<T>, WeakMap<K, V> and WeakSet<T> take their key and value types as type arguments. In a .js file you cannot write new Map<string, number>(), so give the variable the type with @type {Map<string, number>} and create it with new Map().
Without a type and without initial entries, new Map() is Map<any, any> and checks nothing, as the last example shows. With initial entries, new Map([["TEE-01", 12]]) infers Map<string, number> from them.
At a glance
| Use | JSDoc in a .js file | TypeScript in a .ts file |
|---|---|---|
| A Map | /** @type {Map<string, number>} */
const stock = new Map(); | const stock = new Map<string, number>(); |
| A Set | /** @type {Set<string>} */
const tags = new Set(); | const tags = new Set<string>(); |
| A WeakMap | /** @type {WeakMap<HTMLElement, number>} */ | : WeakMap<HTMLElement, number> |
Examples
/** @type {Map<string, number>} */
const stock = new Map([["TEE-01", 12]]);
/** @type {Set<string>} */
const tags = new Set(["cotton", "summer"]);
/** @type {WeakMap<HTMLElement, { clicks: number }>} */
const stats = new WeakMap();
stock.set("MUG-07", 3);
tags.add("sale");
/** @param {HTMLElement} el */
export function track(el) {
const entry = stats.get(el) ?? { clicks: 0 };
entry.clicks += 1;
stats.set(el, entry);
}
export { stock, tags };const stock: Map<string, number> = new Map([["TEE-01", 12]]);
const tags: Set<string> = new Set(["cotton", "summer"]);
const stats: WeakMap<HTMLElement, { clicks: number }> = new WeakMap();
stock.set("MUG-07", 3);
tags.add("sale");
export function track(el: HTMLElement) {
const entry = stats.get(el) ?? { clicks: 0 };
entry.clicks += 1;
stats.set(el, entry);
}
export { stock, tags };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /** @type {Map<string, number>} */
const stock = new Map();
stock.set("TEE-01", 12);
stock.set("MUG-07", "3");error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
export { stock };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} /** @type {Map<string, number>} */
const stock = new Map([["TEE-01", 12]]);
const left = stock.get("TEE-01") - 1;error TS2532: Object is possibly 'undefined'.
const safe = (stock.get("TEE-01") ?? 0) - 1;
export { left, safe };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} // No type: both lines pass, because the Map is Map<any, any>.
const stock = new Map();
stock.set(1, "twelve");
export { stock };jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} get() may miss
Map.prototype.get returns V | undefined, so using the result directly is an error (TS2532 in the third example). Handle the miss with ??, an if, or a has() check followed by a get() (TypeScript does not connect the two calls, so you may still need the ??).
WeakMap and WeakSet
Weak collections need object keys, so their key type must be an object type such as HTMLElement or object; a string key is an error. They suit data attached to DOM nodes or other objects you do not own.
Gotchas
- Class fields work the same way:
/** @type {Map<string, Product>} */ #byId = new Map();. - Iterating a
Mapgives[K, V]tuples, sofor (const [sku, count] of stock)types both.
Questions
How do I type a Map in JSDoc?
Put the type on the variable: /** @type {Map<string, number>} */ const stock = new Map();. The type arguments then apply to every get, set and loop.
Sources
- Generics: generic types · TypeScript handbook
- Map · MDN
- WeakMap · MDN
Last reviewed 20 October 2026.