TypeScript Objects as Dictionary types as in C#
In newer versions of typescript you can use:
type Customers = Record<string, Customer>
In older versions you can use:
var map: { [email: string]: Customer; } = { };map['foo@gmail.com'] = new Customer(); // OKmap[14] = new Customer(); // Not OK, 14 is not a stringmap['bar@hotmail.com'] = 'x'; // Not OK, 'x' is not a customer
You can also make an interface if you don't want to type that whole type annotation out every time:
interface StringToCustomerMap { [email: string]: Customer;}var map: StringToCustomerMap = { };// Equivalent to first line of above
In addition to using an map-like object, there has been an actual Map
object for some time now, which is available in TypeScript when compiling to ES6, or when using a polyfill with the ES6 type-definitions:
let people = new Map<string, Person>();
It supports the same functionality as Object
, and more, with a slightly different syntax:
// Adding an item (a key-value pair):people.set("John", { firstName: "John", lastName: "Doe" });// Checking for the presence of a key:people.has("John"); // true// Retrieving a value by a key:people.get("John").lastName; // "Doe"// Deleting an item by a key:people.delete("John");
This alone has several advantages over using a map-like object, such as:
- Support for non-string based keys, e.g. numbers or objects, neither of which are supported by
Object
(no,Object
does not support numbers, it converts them to strings) - Less room for errors when not using
--noImplicitAny
, as aMap
always has a key type and a value type, whereas an object might not have an index-signature - The functionality of adding/removing items (key-value pairs) is optimized for the task, unlike creating properties on an
Object
Additionally, a Map
object provides a more powerful and elegant API for common tasks, most of which are not available through simple Object
s without hacking together helper functions (although some of these require a full ES6 iterator/iterable polyfill for ES5 targets or below):
// Iterate over Map entries:people.forEach((person, key) => ...);// Clear the Map:people.clear();// Get Map size:people.size;// Extract keys into array (in insertion order):let keys = Array.from(people.keys());// Extract values into array (in insertion order):let values = Array.from(people.values());
You can use templated interfaces like this:
interface Map<T> { [K: string]: T;}let dict: Map<number> = {};dict["one"] = 1;