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:

Output with ReadOnly array:

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 propertyOutput:

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:

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:

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 fineThe 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:

This approach offers two benefits:
- It documents that the function won’t modify the input array.
- 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:
- Use readonly for API responses: When fetching data from APIs, mark the returned arrays as readonly to prevent accidental modifications.
- Prefer readonly parameters: For functions that don’t need to modify their array inputs, always use readonly array parameters.
- Create copies when needed: If you need to modify a readonly array, create a copy using the spread operator.
- 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:

// 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 propertyOutput:

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:
- Configuration data: Settings that shouldn’t change after initialization
- API responses: Data from external sources you want to keep pristine
- Function parameters: Inputs that shouldn’t be modified by the function
- Constants: Values that are fundamentally immutable by design
- 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.

I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.