ProgrammingFullstack Developer

How does the mechanism of dynamic additional access to properties (Index Signature) work in TypeScript? What is it used for, and what are the main pitfalls?

Pass interviews with Hintsage AI assistant

Answer.

Index Signature is a mechanism for describing the type of objects whose keys are unknown in advance (or can be dynamically added), and values correspond to a specific type. It allows for the creation of dictionary-like objects (map/dictionary) where the list of properties is not known at compile time.

Background: in JavaScript, objects often act as associative arrays. The static typing of TypeScript requires specifying the types of keys and values. The Index Signature addresses the main task: to describe an object where the key is not a rigidly defined property, but a string (or number), and the values are of a specific type.

Problem: when working with such objects, you can encounter situations where known properties of the object conflict with the index signature, or information about specific properties is lost. There are nuances with inherited types and expanding the structure of a dictionary.

Solution: The Index Signature is used to describe dynamic properties, usually with a key type of string or number, for example for collections, cache objects, or API responses of the form { [key: string]: T }. To maintain control over the type, it’s necessary to describe both fixed properties and the index signature together, or, if needed, to create union types.

Example code:

interface StringNumberMap { [key: string]: number; } const map: StringNumberMap = { apples: 2, oranges: 5, bananas: 3 };

Key features:

  • Allows describing objects with a dynamic set of properties
  • The key can be string, number, symbol
  • The index signature affects the typing of all properties of the object

Tricky questions.

What happens if you add a fixed property with an incompatible type to an interface with an index signature?

TypeScript will raise an error if the property type is not compatible with the type specified in the index signature.

interface BadDict { [key: string]: number; error: string; // Error: string is not compatible with number }

Can multiple index signatures with different key types (number and string) be declared at the same time?

Yes, but there is a nuance: in TypeScript, keys of type number are automatically converted to string. An index signature with number is merely a synonym for string keys.

interface NumStrDict { [key: string]: number; [key: number]: number; }

Can union types or interfaces be used for the value in an index signature?

Yes, the value can be a union type or an interface. This allows for describing dictionaries of complex objects.

interface Dict { [key: string]: string | number; }

Common mistakes and anti-patterns

  • Type incompatibility between fixed properties and the index signature
  • Using any type of value (e.g., [key: string]: any)
  • Gaps in documentation, unclear what can be a key

Real-life example

Negative case

In the interface of an API response, [key: string]: any was used. Later, the returned object contained data of different structures, leading to runtime errors and complicating code maintenance.

Pros:

  • Quick description of an arbitrary structure
  • Simplicity in use

Cons:

  • Easy to make typing errors
  • Opacity of object structures

Positive case

An interface for a cache object was described, where values are of a strictly defined type (e.g., UserData), with a comment that the key is userId (string):

interface UserCache { [userId: string]: UserData; }

Pros:

  • Clear typing
  • Easy to use and extend

Cons:

  • Does not protect against incorrect use of keys
  • Can be challenging to combine with fixed properties