Differences and Usage of as const and Readonly in TypeScript

tommykw

Kenji Tomita

Posted on July 28, 2024

Differences and Usage of as const and Readonly in TypeScript

In TypeScript, you can use as const and Readonly to specify types more strictly for objects and arrays. This article explains the differences and usage of these features.

Basic Task List Example

Here is an array of objects with description and completed properties.

const tasks = [
  {
    description: 'Buy groceries',
    completed: false,
  },
  {
    description: 'Clean the house',
    completed: true,
  },
  {
    description: 'Finish project',
    completed: false,
  },
]
Enter fullscreen mode Exit fullscreen mode

In this case, the properties of each object are mutable.

Example with as const

Using as const makes each object treated as a literal type, making them immutable.

const tasks = [
  {
    description: 'Buy groceries',
    completed: false,
  },
  {
    description: 'Clean the house',
    completed: true,
  },
  {
    description: 'Finish project',
    completed: false,
  },
] as const;

tasks.push({description: 'Buy milk', completed: false}) // Error
tasks[0].description = 'Buy milk' // Error
Enter fullscreen mode Exit fullscreen mode

The above code translates to the following type:

const tasks: readonly [{
  readonly description: "Buy groceries";
  readonly completed: false;
}, {
  readonly description: "Clean the house";
  readonly completed: true;
}, {
  readonly description: "Finish project";
  readonly completed: false;
}]
Enter fullscreen mode Exit fullscreen mode

Each object is treated as part of a readonly array, making operations like adding or removing elements impossible. Additionally, the properties of each object are readonly, preventing any changes to their values.

For example, if there is an unintended property like below, it results in an error during type checking.

const tasks = [
  {
    description: 'Buy groceries',
    completed: false,
  },
  {
    description: 'Clean the house',
    completed: true,
  },
  {
    descriptionnnnnnnn: 'Finish project',
    completed: false,
  },
] as const;

tasks.forEach((task) => {
  console.log(task.description); // Error
})
Enter fullscreen mode Exit fullscreen mode

Example with as const satisfies

While as const makes the elements readonly and literal types, as const satisfies combines literal types with type constraints.

const tasks = [
  {
    description: 'Buy groceries',
    completed: false,
  },
  {
    description: 'Clean the house',
    completed: true,
  },
  {
    description: 'Finish project',
    completed: false,
  },
] as const satisfies { description: string, completed: boolean }[]
Enter fullscreen mode Exit fullscreen mode

The above code translates to the following type:

const tasks: [{
  readonly description: "Buy groceries";
  readonly completed: false;
}, {
  readonly description: "Clean the house";
  readonly completed: true;
}, {
  readonly description: "Finish project";
  readonly completed: false;
}]
Enter fullscreen mode Exit fullscreen mode

The elements of the array themselves are readonly, but the array itself is not. This means you can change the elements of the array but not the properties within the elements.

Using satisfies, you ensure that each object conforms to a specific type ({ description: string, completed: boolean } in this case).

const tasks = [
  {
    description: 'Buy groceries',
    completed: false,
  },
  {
    description: 'Clean the house',
    completed: true,
  },
  {
    descriptionnnnnnnn: 'Finish project', // Error
    completed: false,
  },
] as const satisfies { description: string, completed: boolean }[]
Enter fullscreen mode Exit fullscreen mode

Example with Readonly

Using Readonly makes the properties of the object immutable.

const tasks: Readonly<{ description: string, completed: boolean }>[] = [
  {
    description: 'Buy groceries',
    completed: false,
  },
  {
    description: 'Clean the house',
    completed: true,
  },
  {
    description: 'Finish project',
    completed: false,
  },
];

tasks.push({description: 'Buy milk', completed: false}) // OK
tasks[0].completed = true // Error
Enter fullscreen mode Exit fullscreen mode

The above code translates to the following type:

const tasks: Readonly<{
  description: string;
  completed: boolean;
}>[]
Enter fullscreen mode Exit fullscreen mode

All properties of the array elements are readonly, making them immutable. However, you can still add or remove elements from the array.

Summary

In this article, we introduced the usage and differences between as const, as const satisfies, and Readonly. By using these features, you can manage types more strictly in TypeScript and prevent unintended changes.

💖 💪 🙅 🚩
tommykw
Kenji Tomita

Posted on July 28, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related