DEV Community

Kenji Tomita
Kenji Tomita

Posted on

Learning TypeScript's Record Type

TypeScript provides several useful utility types, among which Record is particularly valuable for defining an object type where specific keys K are mapped to values of type T. Introduced in TypeScript 2.1, Record is a flexible way to define object types.

1. What is Record?

Record is a utility type that allows specifying the keys of an object using K while ensuring all values conform to the type T.

Basic Syntax

type Record<K extends keyof any, T> = {
    [P in K]: T;
};
Enter fullscreen mode Exit fullscreen mode

This is a Mapped Type, where each key P in K is mapped to value of type T.

2. Basic Usage of Record

Basic Example

const httpStatusMessages: Record<number, string> = {
  200: "OK",
  404: "Not Found",
  500: "Internal Server Error",
};
Enter fullscreen mode Exit fullscreen mode

In this example, keys are of type number (representing HTTP status codes), and their corresponding values are of type string.

3. Benefits of Record

(1) Restricting Key Types

type StatusCode = 200 | 404 | 500;

const statusMessages: Record<StatusCode, string> = {
  0: 'Unknown', // Object literal may only specify known properties, and '0' does not exist in type 'Record<StatusCode, string>'.
  200: "OK",
  404: "Not Found",
  500: "Internal Server Error",
};
Enter fullscreen mode Exit fullscreen mode

Using an unspecified key results in an error, improving type safety.

(2) Ensuring Type Consistency

type StatusCode = 200 | 404 | 500;

const statusMessages: Record<StatusCode, string> = { // Property '200' is missing in type '{ 404: string; 500: string; }' but required in type 'Record<StatusCode, string>'.
  404: "Not Found",
  500: "Internal Server Error",
};
Enter fullscreen mode Exit fullscreen mode

All keys must be defined, preventing missing values.

One of the key benefits of Record is that it ensures all specified keys are present in the object. This is because it is implemented as a mapped type, meaning that TypeScript expects every key from K to be explicitly defined.

type StatusCode = 200 | 404 | 500;

const statusMessages: {[key in StatusCode]: string} = {
  200: "OK",
  404: "Not Found",
  // 500 is missing, so TypeScript throws an error
};
Enter fullscreen mode Exit fullscreen mode

This expands into:

type StatusMessagesType = {
  200: string;
  404: string;
  500: string;
};
Enter fullscreen mode Exit fullscreen mode

Since 500 is missing in the object, TypeScript will throw an error stating that the property 500 is required but not provided. This ensures that all possible keys are accounted for, reducing potential runtime errors.

(3) Handling Dynamic Keys

const dynamicData: Record<number, string> = {};

dynamicData[1] = "Hello";
dynamicData[2] = "World";
Enter fullscreen mode Exit fullscreen mode

Keys can be added dynamically, which is a key strength of Record.

4. When to use Alternatives to Record

(1) When Using Constant Objects

Using as const ensures that values remain literal types, improving type safety.

type StatusCode = 200 | 404 | 500;

const statusMessages = {
  200: "OK",
  404: "Not Found",
  500: "Internal Server Error",
} as const;

statusMessages[200] = "NG"; // Cannot assign to '200' because it is a read-only property.
Enter fullscreen mode Exit fullscreen mode

5. Conclusion

Record is a powerful utility type in TypeScript that ensures uniform key-value relationships. It is especially useful when restricting key types while maintaining type consistency.

Top comments (0)