ProgrammingFullstack Developer

How do Indexed Access Types (like T[K]) work? When to use them, how to avoid errors when changing the type structure, and what is their role in complex objects?

Pass interviews with Hintsage AI assistant

Answer

Indexed Access Types (or index access types) allow referring to the type of a specific property of an object or any key through the syntax T[K]. This is a powerful tool for creating flexible and type-safe abstractions.

Example:
type Person = { name: string; age: number; }; type NameType = Person['name']; // string type AgeOrName = Person['age' | 'name']; // number | string

Used for writing generic types and functions:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; // correct return type } const user = { email: 'a@a.ru', id: 1 }; let id = getProperty(user, 'id'); // id: number

Purpose:

  • To create type constructors (for example, extracting the type of a value by key from complex nested structures).
  • Building associated types (Record, Pick, etc.)

Nuances:

  • When the original type (Person) is changed, the result of index access also changes, which can unexpectedly affect bindings everywhere!
  • TS does not catch the situation if the key does not exist: Person['salary'] – a compile-time error.

Trick Question

Question: What type will the expression type Foo = {a: number, b: string}["a" | "b" | "c"] produce?

Answer: This example will cause a compile error because 'c' is not a key in the type being accessed. TypeScript will throw the error:

Type '"c"' does not satisfy the constraint '"a" | "b"'.

Examples of real errors due to ignorance of nuances of the topic.


Story

In the project, forms were dynamically generated based on types. After adding a new field to the main type, the indexed access locations weren't updated, and as a result, some properties did not make it into the form, although a complete mapping was expected at the type level. The error only manifested at runtime, not at development time.


Story

In a data validation library, indexed access was used through types, but when migrating the code, one of the keys was moved from the object to the parent. The old indexed type led to a compile error; however, the error only arose after rebuilding due to CI caching, and before that, it lived on staging for several weeks.


Story

It was mistakenly believed that Indexed Access Types could be used to access any key, even if it was not explicitly listed, which led to incorrect auto-test generation for dynamic properties. As a result, tests did not cover part of the possible scenarios as the compiler threw these cases as invalid.