Last updated: Feb 27, 2024
Reading timeยท5 min
One way to define a key-value pair in TypeScript is to use an index signature.
An index signature is used when we don't know all the names of a type's keys ahead of time, but we know the shape of their values.
const employee: { [key: string]: string | number } = {}; employee.name = 'Bobby Hadz'; employee.salary = 100; // ๐๏ธ { name: 'Bobby Hadz', salary: 100 } console.log(employee);
The {[key: string]: string}
syntax is an
index signature in TypeScript and is used
when we don't know all the names of a type's properties ahead of time but know
the shape of the values.
string
, it will return a value of type string
or number
.You might also see the index signature {[key: string]: any}
in examples.
It represents a key-value structure that when indexed with a string returns a
value of any
type (very broad).
const employee: { [key: string]: any } = {}; employee.name = 'Bobby Hadz'; employee.salary = 100; employee.years = [2023, 2024]; // ๐๏ธ { name: 'Bobby Hadz', salary: 100, years: [ 2023, 2024 ] } console.log(employee);
The {[key: string]: any}
index signature is used to create a key-value pair
when we don't know the names of a type's keys and the shape of the values ahead
of time.
You can declare the types of the keys and values that you know ahead of time and
use an any
type for the ones you don't.
type Employee = { [key: string]: any; name: string; salary: number; }; const employee: Employee = { name: 'Bobby Hadz', salary: 100, }; employee.country = 'Bobby Hadz'; employee.years = [2021, 2022];
We declared types for the name
and salary
properties, which we know about
ahead of time and used an index signature to still allow us to assign any key
with any value to the object.
This is useful because we still get type support for the name
and salary
properties and the type checker would throw an error if we tried to set the
properties to an incompatible type.
You can use a Map to define a key-value pair. A generic is used to set the type of the Map's keys and values.
const map1 = new Map(); map1.set('name', 'Bobby Hadz'); map1.set('age', 30); map1.set('country', 'Germany'); // ๐๏ธ { 'name' => 'Bobby Hadz', 'age' => 30, 'country' => 'Germany' } console.log(map1); // ๐๏ธ Bobby Hadz console.log(map1.get('name'));
The Map in the example is implicitly typed to have keys and values of any type, but you can also explicitly specify a type.
const map1 = new Map<string, string | number>(); map1.set('name', 'Bobby Hadz'); map1.set('age', 30); map1.set('country', 'Germany'); console.log(map1); // ๐๏ธ Bobby Hadz console.log(map1.get('name'));
We used a generic to declare a Map that has
string keys and string
or number
values.
The syntax that is used to type a Map is -
new Map<TypeOfKeys, TypeOfValues>()
.
For example, new Map<number, string>
is a Map object with keys of type
number
and values of type string
.
All of the key-value pairs we add to the Map have to conform to the specified types, otherwise, an error is thrown.
const map1 = new Map<string, string | number>([ ['name', 'Bobby Hadz'], ['age', 30], ]); // โ๏ธ Error: Argument of type 'boolean' is not // assignable to parameter of type 'string | number'.ts(2345) map1.set('country', true);
We used a union type to set the Map's values to be either strings or numbers, but a boolean value is not a member of the union, so we got an error.
We typed the values of the Map
to be strings or numbers, so when we
use the
Map.get()
method, we will get a value of type string
, number
or undefined
.
const map1 = new Map<string, string | number>([ ['name', 'Bobby hadz'], ['age', 30], ['country', 'Germany'], ]); // ๐๏ธ const country: string | number | undefined const country = map1.get('country'); if (typeof country === 'string') { // ๐๏ธ GERMANY console.log(country.toUpperCase()); }
country
variable is possibly undefined
because TypeScript can't know in advance whether the Map contains a country
key.The if
statement serves as a
type guard because it directly checks
for the type of the value. The country
variable is guaranteed to be a string
in the if
block.
You can use the Map.set() method to add a key-value pair to the Map.
const map1 = new Map<string, string | number>([ ['name', 'Bobby Hadz'], ['age', 30], ]); map1.set('country', 'Germany'); console.log(map1.get('country')); // ๐๏ธ "Germany" console.log(map1.delete('country')); // ๐๏ธ true console.log(map1.has('country')); // ๐๏ธ false
Make sure that the type of the key
and value you passed to the Map.set()
method conform to the types you specified when defining the Map.
The code sample shows how to use the Map.delete()
method to remove a key-value
pair from the Map.
Map.delete()
method returns true
if an element in the Map object existed and has been removed, otherwise false
is returned.The Map.has()
method returns true
if the specified key exists in the Map
.
You can use the Map.forEach method to iterate over a Map in TypeScript.
const map1 = new Map<string, string | number>([ ['name', 'Bobby Hadz'], ['age', 30], ]); map1.forEach((value, key) => { console.log(value, key); // ๐๏ธ Bobby Hadz name, 30 age }); for (const [key, value] of map1) { console.log(key, value); // ๐๏ธ name Bobby Hadz, age 30 }
The Map.forEach()
method and a for...of
loop can be used to iterate over a
Map
.
The for...of
loop might be your preferred approach if you have to use the
break
keyword to exit the loop prematurely.
Using the break
keyword is not supported in the forEach
method.
Something you might often need is to convert the Map's keys or values to an array, because arrays have many useful built-in methods.
const map1 = new Map<string, string | number>([ ['name', 'Bobby Hadz'], ['age', 30], ]); const values = Array.from(map1.values()); console.log(values); // ๐๏ธ ['Bobby Hadz', 30] const keys = Array.from(map1.keys()); console.log(keys); // ๐๏ธ ['name', 'age']
We used the
Map.values()
method to get an iterator object containing the values of the Map
.
We passed the iterator as the only parameter to the Array.from() method.
The Array.from()
method converts the iterable into an array and returns the
new array instance.
Another common thing you might need is to check how many elements a Map has. The Map.size() method returns the number of elements in the Map.
const map1 = new Map<string, string | number>([ ['name', 'Bobby Hadz'], ['age', 30], ]); console.log(map1.size); // ๐๏ธ 2 map1.set('country', 'Germany'); console.log(map1.size); // ๐๏ธ 3
If you need to remove all key-value pairs from a Map object, use the Map.clear() method.
const map1 = new Map<string, string | number>([ ['name', 'Bobby Hadz'], ['age', 30], ]); map1.clear(); console.log(map1.size); // ๐๏ธ 0
You can learn more about the related topics by checking out the following tutorials: