Record in TypeScript: what it is and how to use it for beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Record in TypeScript: a practical breakdown

\n\n

Imagine you are writing an app for learning English words. You need to store translations: cat → кошка, dog → собака. How do you properly type this in TypeScript? You could create an interface, but what if the keys are unknown in advance? Or there are too many of them? That's where Record comes to the rescue — one of the most useful, yet often underestimated, utility types.

\n\n

In this article, we'll break down what the Record type in TypeScript is, using real-world examples that you can immediately apply in your projects. No boring theory — just practice.

\n\n

What is Record in TypeScript? In simple terms

\n\n

Record<K, V> is a built-in utility type that creates an object where all keys are of type K and all values are of type V.
Think of it as a typed dictionary or a map with a fixed set of keys.

\n\n

The basic syntax looks like this:

\n\n
// A regular object\nconst userRoles: Record<string, string> = {\n  admin: 'Администратор',\n  user: 'Пользователь',\n  guest: 'Гость'\n};
\n\n

Here, Record<string, string> means: "An object where keys are strings, and values are also strings." Simple and clear.

\n\n

Why is Record better than a regular interface?

\n\n
    \n
  • Key flexibility: You can specify a specific set of keys using a union type.
  • \n
  • Conciseness: No need to describe each field manually.
  • \n
  • Safety: TypeScript will check that you only use allowed keys.
  • \n
\n\n

Record vs a plain object: a clear example

\n\n

Let's say we have order statuses: pending, shipped, delivered. Without Record, you would have to write an interface with three fields:

\n\n
interface OrderStatusMap {\n  pending: string;\n  shipped: string;\n  delivered: string;\n}\n\nconst statusDescriptions: OrderStatusMap = {\n  pending: 'Ожидает обработки',\n  shipped: 'Отправлен',\n  delivered: 'Доставлен'\n};
\n\n

But with Record, it's more compact and clearer:

\n\n
type OrderStatus = 'pending' | 'shipped' | 'delivered';\n\nconst statusDescriptions: Record<OrderStatus, string> = {\n  pending: 'Ожидает обработки',\n  shipped: 'Отправлен',\n  delivered: 'Доставлен'\n};
\n\n

Plus: if you try to add cancelled to the object, TypeScript will immediately point out the error — that status doesn't exist in the union type.

\n\n

Top 5 practical examples of using Record

\n\n

Let's look at where Record really simplifies life.

\n\n

1. Application configuration

\n

Store settings with known keys but different value types:

\n\n
type ConfigKeys = 'apiUrl' | 'timeout' | 'retryCount';\ntype ConfigValue = string | number | boolean;\n\nconst appConfig: Record<ConfigKeys, ConfigValue> = {\n  apiUrl: 'https://api.example.com',\n  timeout: 5000,\n  retryCount: 3\n};
\n\n

2. Mapping enums or constants

\n

Often you need to map a code to its human-readable name:

\n\n
enum HttpStatus {\n  OK = 200,\n  NotFound = 404,\n  Error = 500\n}\n\nconst statusMessages: Record<HttpStatus, string> = {\n  [HttpStatus.OK]: 'Всё хорошо',\n  [HttpStatus.NotFound]: 'Не найдено',\n  [HttpStatus.Error]: 'Ошибка сервера'\n};
\n\n

3. Forms and validation

\n

Record is perfect for storing validation errors by field:

\n\n
type FormFields = 'email' | 'password' | 'name';\ntype ValidationErrors = Record<FormFields, string | null>;\n\nconst errors: ValidationErrors = {\n  email: 'Некорректный email',\n  password: null,\n  name: 'Имя обязательно'\n};
\n\n

4. Data caching

\n

Simulating a cache with identifier keys:

\n\n
type UserI                

Blogs

Book Recommendations