Dictionary in TypeScript

Learn via video courses
Topics Covered

Overview

JavaScript is a superset of TypeScript. Superset indicates that it adds functionalities to typescript which JavaScript already has in its libraries. TypeScript extends the functionalities and structures provided by JavaScript as a language by adding a few new features. JavaScript was launched as a client-side language. JavaScript has emerged as an emergent server-side technology as a result of the creation of Node.js.

Introduction

Collections of key-value pairs, often known as dictionaries, associative arrays, maps, hashes, or objects, are essential components of most computer programs. JavaScript has a couple good and simple approaches for constructing dictionaries. When you begin working with types in TypeScript. You should be more selective in your selections.

A dictionary in typescript is a type of data structure that is commonly used in computer languages. It is critical for JavaScript developers to deal with type-safe dictionaries since storing multiple types of data within the same dictionary can result in conflicts or unforeseen consequences.

In this post, we'll look at how to use TypeScript to create a type-safe dictionary in typescript. But first, let’s understand what exactly is this Dictionary in Typescript?

Dictionary in Typescript

Collections of key-value pairs, often known as dictionaries, associative arrays, maps, hashes, or objects, are an essential component of most computer programs.

JavaScript has a couple good and simple approaches for constructing dictionaries. When working with types in TypeScript, you must be more selective in your decisions.

The 'object' is the most often used implementation for dictionaries in JavaScript. As an example, consider the following:

We have a mapping of strings to integers here. In this mapping, the keys are the names of fictitious characters, and the values represent the number of superheroes such characters have.

It is simple to access a value in an object:

Defining "Present" and "Valid" Keys, as Well as The Keyspace of A Dictionary in Typescript

A dictionary's keyspace and keyset are important qualities.

The keyspace of a dictionary in typescript is the set of keys that can be regarded as valid for that dictionary. Consider student, a dictionary that matches the names of a school's adolescent students to their current age. In this scenario, the keyspace would be ["Sahil", "Atul", "Priya", "Ashu"]. It's a tiny and bounded keyspace, which means we know how big it is and what values it contains.

We have a different scenario now, thanks to our name age dictionary. It would be impracticable to try to list every potential valid key because a key may be any imaginary character. The keyset of a dictionary is the set of keys that are currently defined within that typescript dictionary. It may be tempting to define the keyset as the set of keys that have a value associated with them, however, JavaScript allows for something like:

As a result, we continue with the original definition.

A keyspace is a typescript dictionary-type property. A keyset is a dictionary value's attribute. Many dictionaries have a greater keyspace than any feasible keyset. A sparse dictionary in typescript is one in which the keyspace and keyset are not identical. Otherwise, we declare it finished.

The Object Functions

Several JavaScript methods are available for turning an object-based dictionary in typescript into usable arrays.

Object.keys will return an array of an object's keys: [key1, key2, key3,...]. This is the keyset of the dictionary.

Object.values returns an array of an object's values: [value1, value2, value3,...].

Object.entries returns an array of key-value pairs from an object: [[key1, value1], [[key2, value2], [key3, value3],...].

What is a Type-safe Dictionary?

You may now add type-safety to your dictionaries thanks to the introduction of TypeScript. This gives you complete control over the keys you utilize and the values you add to your dictionaries. It also enables you to make claims about the values returned by your dictionaries. A dictionary in typescript is a common data structure in computer languages that hold data in key-value pairs. However, there is no Dictionary type in JavaScript. Fortunately, we can create a type-safe dictionary in a few simple steps.

  • declare and initialize a map variable
  • Combine the key-value pairs.
  • check whether the key exists
  • Obtain the value using a key.
  • Remove a key and its associated value.
  • Iterate across the map, adding keys and values as you go.
  • A map's components must all be removed.
  • calculate the number of items in a map

The type of an object-based typescript dictionary may be defined in two ways in the most recent version of TypeScript:

The indexed object has the advantage of more clearly expressing the object key's intent. It is, however, more verbose, and if your key is self-documenting (for example, an enum), Record may be a better alternative.

The two procedures described above are similar in terms of type-checking. They limit the key type to string and the value type to numeric.

As a result, the type you give to your key specifies its keyspace. Because the string type in the above example allows for any string, the keyspace is virtually unlimited.

Problems with Object-Based Dictionaries that Are Sparse

When using a sparse dictionary in typescript, you know that if you try to retrieve a value at a key that is not in the dictionary's keyset, you will get undefined in response:

As a result, you may presume that the type of superhero is number | undefined.

TypeScript, unfortunately, thinks that your objects are complete. This means that superhero is treated as a basic numeric type. This can lead to a slew of issues. First, the type contract is violated; you have the variable superhero that is written as numbers but can be undefined. Also, if you try to type-check superhero to see whether they are undefined, your linter or IDE may complain about an unnecessary type-check.

This solves your simple value-access issue. The format is right. However, this violates the Object functions' return types.

Object.values returns an array of all the values presently available in the object. However, if you've specified that your value type is number | undefined, you must explicitly type-check each value to ensure type safety:

The same may be said for Object.entries.

Remember that this is only an issue with small vocabularies. Using indexed object types or Records is good if your keyspace is tiny and every key has a value.

the Most Effective Technique to Express Sparse Dictionaries

Typescript dictionary support is provided by both JavaScript and TypeScript . They supply a Map implementation. (There's also a WeakMap that limits key types to objects.) Its other distinctions are irrelevant to this debate).

Using a Map to construct a type-safe, sparse dictionary in typescript is a far superior method. There are two methods for creating a Map:

Remember that the Map is not a substitute for an object You cannot set values to object keys and expect the Map to work properly. Furthermore, object keys cannot be read directly. Get and set must be used instead.

As you can see, the right kind is linked to heroes in this case. You may then use a type guard to figure out which kind you have.

A Map provides methods for keys, values, and entries. These return Iterators rather than arrays, but because they are appropriately typed, you won't have to add type guards to assure type safety when interacting with them. To turn an iterator into an array, you can always use Array.from.

Using Object Types in JavaScript

In JavaScript, there are two ways to generate a dictionary: utilizing the Object type and using key-value pairs. The most common JavaScript approach is to build one with the Object type. Let's make a dictionary with the code below:

With the original data as key-value pairs, we can form a dictionary:

We constructed the Literaldictionary, which is a dictionary containing key and value string types.

If you wish to edit or add a value to the dictionary, you may do so by calling on the dictionary key, as seen below:

We can get the value from the dictionary by calling the property name or indexer directly:

Using Map in JavaScript

Before directly going to using Map in Javascript let's understand what is Map first?

What is a Map in JavaScript?

A map is a collection of key/value pairs that may utilize any form of data as a key or value and remember the order in which its items are entered. It is used to iterate through all of the elements in an array, resulting in a new array. In other words, you can take an array, alter the elements, and obtain a new array based on what the function returns. This is why maps are important for quick data searching and retrieval.

Before the introduction of the map, you had to utilize an object. The disadvantage of utilizing an object is that it restricts keys to only texts or numbers.

Map, on the other hand, permits keys to be arrays, objects, integers, and so forth.

The ability to traverse through the data structures in the sequence in which the items were added is the most significant enhancement of the map feature. When utilizing map, you may add/delete new and existing keys as well as get their values.

Use of a Map in Javascript?

When you want to conduct an action on each element in a collection and collect the results in a new array, you may use Map. The 'for loop' or 'nesting' in JavaScript may do the same thing, but we can utilize map() to build more legible functions.

The new Map() syntax allows you to construct and initialize a Map. You have the option of subsequently setting a value to it.

In this case, we made a new Map named firstMap. When the code is executed, it produces an empty map. Please see the following:

A Map, like an object, is a collection of key-value pairs. The biggest distinction is that Map lets you utilize any kind of key and value. The Map gives fantastic instance methods for interacting with a dictionary.

You can alternatively build a new Map object by supplying an array to new Map(). We'll make a new Map object with a key of some popular songs and the value of the artist's name. Look at the output below:

Also because Map stores value by any type of key, they return two distinct values:

To change values in the Map dictionary, we must use the set method by key:

Dictionary Type Errors in TypeScript

We'll get issues if we use the dictionary in TypeScript after using it in JavaScript since TypeScript has to understand the data type of an object before it could be accessed.

This implies that the following code will run without error in JavaScript but will fail in TypeScript. Let us investigate.

In this case, sample_dictionary.lastName returns undefined in JavaScript but throws an error in TypeScript.

Sure, we could use type any in our code, however why use TypeScript if we aren't going to type check?

We've seen Dictionary Type problems in Typescript; now let's learn how to handle them smoothly.

Returning Null

Returning null is a standard situation to notify that anything went wrong in your function. It is best utilized when there is just one way for a function to fail; nonetheless, some developers use it when a function has several mistakes.

Returning null in TypeScript imposes null checks across your code, resulting in the loss of particular information about the origin of the problem. Because returning null is an arbitrary expression of an error, you'll get the same result if you try returning 0, -1, or false.

In the code block below, we'll construct a function that obtains temperature and humidity statistics for a certain city. The Weather function communicates with two external APIs, externalTemperature and externalHumidity, and combines the results:

We can see that when we enter Pune, the error messages Error in getting temperature for $city and Error in fetching humidity for $city appear.

Because both of our external API operations might fail, Weather is compelled to check for null for both. Although testing for null is preferable than not handling errors at all, it requires the caller to make some educated estimates. If a function is expanded to accommodate a new error, the caller will not be aware of it until they inspect the function's inner workings.

Assume that when the temperature API returns HTTP code 500, which signals an internal server fault, externalTemperature initially throws a null. If we modify our function to verify the structural and type validity of the API response (i.e., check that the response is of type number), the caller will have no idea whether the function returns null due to HTTP code 500 or an unexpected API response structure.

Building a Type-safe Dictionary in TypeScript

In TypeScript, there are three techniques to prevent type problems.

Using Indexed Object Notation

Using indexed object notation, we can determine the nature of data. Let's make a dictionary containing key and value strings:

We may give the key whatever name we desire. In this case, I'd want to call it crucial. According to the syntax guideline, we also cannot omit the key name or utilize union types.

Let's make our example more complex:

If we wish to leave out a property, we may utilize Partial utils.

Using the Record<Keys, Type> Utility

The Record<Keys, Type> TypeScript tool is used to create key-value objects. It is an excellent solution for creating key types such as unions or enums.

Using Map in TypeScript

We talked about how to use Map in JavaScript to create type-safe dictionaries. Let's create a basic dictionary in TypeScript with the key as a string and the value as a number:

The key may also be used as a union type and the value as an object type:

Conclusion

  • We can easily work on the data in the dictionary by adding meaningful key names. Such type of straightforward implementation can improve the readability of your code.
  • The indexed object notation may be used to create a basic dictionary.
  • When working with unions, enums, or more complicated data, the Record<Keys, Type> util is recommended.
  • In general, utilizing Map is a really useful solution to address type-safe difficulties with a variety of data types.
  • For a comprehensive dictionary, I would recommend using an indexed object or Record.
  • The syntax is slightly more concise, and the ability to operate on array keys, values, and entries is far more convenient.