How to Use Readonly Arrays in TypeScript?

Recently, I was working on a financial application for an investment firm where data integrity was critical. We needed to ensure that specific arrays of stock prices couldn’t be accidentally modified after initialization.

To handle errors that occur when an array is accidentally changed, we can use read-only arrays to keep the data safe and code easier to manage.

In this tutorial, I’ll explain how to use readonly arrays in TypeScript with the help of real-world examples, best practices, and conversion techniques from regular to readonly arrays.

What Are Readonly Arrays in TypeScript?

Readonly arrays are immutable collections in TypeScript that prevent modifications after initialization. Think of them as arrays with a “look but don’t touch” policy.

Unlike regular arrays, once you create a readonly array, you cannot:

  • Add new elements
  • Remove existing elements
  • Replace elements
  • Use methods that modify the array in place (like push, pop, splice)

Here’s a quick comparison:

// Regular array - fully mutable
const prices: number[] = [105.75, 216.88, 341.29];
prices.push(422.50); // Works fine

// Readonly array - immutable
const readonlyPrices: readonly number[] = [105.75, 216.88, 341.29];
readonlyPrices.push(422.50); // Error: Property 'push' does not exist on type 'readonly number[]'

Output with regular array:

Readonlay Arrays in TypeScript

Output with ReadOnly array:

Array Read Only Object in TypeScript

Different Ways to Create Readonly Arrays in TypeScript

Below are the three methods ‘readonly‘, ‘readonlyarray‘, and ‘as const’ to create readonly arrays in TypeScript.

Check out: Check if an Array is Null or Empty in TypeScript

Method 1: Using the ‘readonly’ Modifier

The simplest way to create a readonly array is by using the readonly modifier:

// Creating a readonly array of stock symbols
const stockSymbols: readonly string[] = ["AAPL", "MSFT", "AMZN", "GOOGL"];

// Trying to modify will cause compile-time errors
stockSymbols[0] = "TSLA"; // Error: Index signature in type 'readonly string[]' only permits reading
stockSymbols.push("NFLX"); // Error: Property 'push' does not exist on type 'readonly string[]'

Method 2: Using ReadonlyArray Type

Another approach is to use the ReadonlyArray<T> type:

// Creating a readonly array of quarterly profits (in millions)
const quarterlyProfits: ReadonlyArray<number> = [125, 156, 132, 142];

// These operations will fail
quarterlyProfits.splice(0, 1); // Error: Property 'splice' does not exist on type 'readonly number[]'
quarterlyProfits.pop(); // Error: Property 'pop' does not exist on type 'readonly number[]'

Method 3: Using ‘as const’ Assertion

The as const assertion creates a deeply immutable array:

// Creating a readonly tuple of company data
const companyData = ["Tesla, Inc.", 2003, "Elon Musk", true] as const;

// This becomes a readonly tuple of exact types: readonly ["Tesla, Inc.", 2003, "Elon Musk", true]
companyData[0] = "SpaceX"; // Error: Cannot assign to '0' because it is a read-only property

Output:

Create Read only arrays in TypeScript

When using as const, TypeScript infers the narrowest possible type for each element, making the entire structure deeply immutable.

Check out: Find the Length of an Array in TypeScript

Practical Examples of Readonly Arrays

Example 1: Preventing Configuration Modifications

// Application configuration settings
const APP_CONFIG: readonly [string, number, boolean] = [
  "US-EAST-1", // AWS region
  30000,       // Timeout in ms
  true         // Debug mode
];

function initializeApp(config: readonly [string, number, boolean]) {
  console.log(`Starting app in ${config[0]} with ${config[1]}ms timeout`);
  // We can be confident that config won't be modified within this function
}

initializeApp(APP_CONFIG);

Example 2: Working with API Response Data

interface StockQuote {
  readonly symbol: string;
  readonly price: number;
  readonly timestamp: Date;
}

// Simulate API response with stock quotes
const getStockQuotes = (): ReadonlyArray<StockQuote> => {
  return [
    { symbol: "AAPL", price: 172.39, timestamp: new Date() },
    { symbol: "MSFT", price: 338.11, timestamp: new Date() },
    { symbol: "AMZN", price: 142.59, timestamp: new Date() }
  ];
};

const quotes = getStockQuotes();

// We can read from quotes
console.log(`Apple stock price: $${quotes[0].price}`);

// But we cannot modify the array
quotes.push({ symbol: "TSLA", price: 244.14, timestamp: new Date() }); // Error!

Output:

Create ReadOnly Arrays in TypeScript

Check out: Iterate Over Arrays in TypeScript

Converting Regular to Readonly Arrays in TypeScript

In the below methods, we will see how we can convert a regular array to a Readonly array and a ReadOnly array to a regular array.

Converting a Regular Array to Readonly

Any regular array can be assigned to a readonly array type:

const cities: string[] = ["New York", "Los Angeles", "Chicago", "Houston"];
const readonlyCities: readonly string[] = cities;

// Original array can still be modified
cities.push("Miami");
console.log(cities); // ["New York", "Los Angeles", "Chicago", "Houston", "Miami"]
console.log(readonlyCities); // ["New York", "Los Angeles", "Chicago", "Houston", "Miami"]

Output:

Handle Read Only arrays in TypeScript

Notice that modifying the original array also changes the readonly reference because they point to the same memory. The readonly type only prevents modifications through the readonly reference.

Converting Readonly Array to Regular Array

Converting from readonly to regular requires an explicit type assertion or spreading:

const readonlyZipCodes: readonly number[] = [10001, 90001, 60007, 77002];

// Using type assertion (not type-safe)
const zipCodes1: number[] = readonlyZipCodes as number[];

// Using spread operator (creates a new array - safer)
const zipCodes2: number[] = [...readonlyZipCodes];

zipCodes2.push(33101); // Works fine

The spread operator approach is safer because it creates a new array rather than just casting the type.

Readonly Arrays in Function Parameters

Using readonly arrays in function parameters is an excellent practice:

function analyzeStockData(data: readonly number[]) {
  // Calculate analytics without modifying the input data
  const average = data.reduce((sum, price) => sum + price, 0) / data.length;
  const max = Math.max(...data);
  const min = Math.min(...data);

  return { average, max, min };
}

const stockPrices = [145.86, 143.21, 147.54, 151.03, 149.84];
const analytics = analyzeStockData(stockPrices);
console.log(analytics); // { average: 147.496, max: 151.03, min: 143.21 }

Output:

Read only arrays in TypeScript functions

This approach offers two benefits:

  1. It documents that the function won’t modify the input array.
  2. It prevents accidental modifications inside the function.

Check out: Append Elements to an Array in TypeScript

Working with Nested Readonly Arrays

For complex data structures, you might need nested readonly arrays:

// Portfolio data with sectors and stocks
const portfolio: readonly (readonly string[])[] = [
  ["Technology", "AAPL", "MSFT", "GOOGL"],
  ["Healthcare", "JNJ", "PFE", "UNH"],
  ["Finance", "JPM", "BAC", "WFC"]
];

// Cannot modify outer array
portfolio.push(["Energy", "XOM", "CVX"]); // Error!

// Cannot modify inner arrays
portfolio[0].push("NVDA"); // Error!

Best Practices for Using Readonly Arrays

After years of working with TypeScript, I’ve developed these best practices:

  1. Use readonly for API responses: When fetching data from APIs, mark the returned arrays as readonly to prevent accidental modifications.
  2. Prefer readonly parameters: For functions that don’t need to modify their array inputs, always use readonly array parameters.
  3. Create copies when needed: If you need to modify a readonly array, create a copy using the spread operator.
  4. Be careful with objects in readonly arrays: Remember that readonly arrays only make the array structure immutable, not the objects within it.
interface User {
  name: string;
  age: number;
}

const users: readonly User[] = [
  { name: "John Smith", age: 35 },
  { name: "Sarah Johnson", age: 28 }
];

// This is still allowed (objects inside are mutable)
users[0].age = 36; // Works!

Output:

Mutable read only array object in TypeScript
// To make everything immutable, use readonly properties
interface ReadonlyUser {
  readonly name: string;
  readonly age: number;
}

const readonlyUsers: readonly ReadonlyUser[] = [
  { name: "John Smith", age: 35 },
  { name: "Sarah Johnson", age: 28 }
];

readonlyUsers[0].age = 36; // Error: Cannot assign to 'age' because it is a read-only property

Output:

Read only property in TypeScript object

Check out:  Merge Arrays of Objects in TypeScript

When to Use Readonly Arrays in TypeScript

Based on my experience, here are scenarios where readonly arrays shine:

  1. Configuration data: Settings that shouldn’t change after initialization
  2. API responses: Data from external sources you want to keep pristine
  3. Function parameters: Inputs that shouldn’t be modified by the function
  4. Constants: Values that are fundamentally immutable by design
  5. State snapshots: Historical records of application state

Readonly arrays have improved my code quality significantly in large applications. They provide clear signals about your intentions and help prevent an entire class of bugs related to unintended mutations.

I hope you found this guide helpful for understanding and implementing readonly arrays in TypeScript. They’re a powerful tool that can make your code more predictable and less prone to bugs.

51 Python Programs

51 PYTHON PROGRAMS PDF FREE

Download a FREE PDF (112 Pages) Containing 51 Useful Python Programs.

pyython developer roadmap

Aspiring to be a Python developer?

Download a FREE PDF on how to become a Python developer.

Let’s be friends

Be the first to know about sales and special discounts.