What is readonly array?
In TypeScript, a `ReadonlyArray` is a special type that ensures an array cannot be modified after its creation. It's a powerful tool for promoting immutability and preventing unintended side effects in your code.
What is a Readonly Array?
A ReadonlyArray<T> is a generic type that represents an array whose elements can be read, but whose structure or contents cannot be changed via methods that mutate the array. This means you cannot add, remove, or reorder elements, nor can you directly assign to an index.
It's important to distinguish ReadonlyArray<T> from a regular array type Array<T> or T[]. While a T[] allows all array operations (reading and mutating), a ReadonlyArray<T> only allows read-only operations.
const numbers: ReadonlyArray<number> = [1, 2, 3];
const names: readonly string[] = ["Alice", "Bob"]; // Shorthand syntax
// You can read elements
console.log(numbers[0]); // Output: 1
console.log(names.length); // Output: 2
Key Characteristics and Limitations
- Immutability: Methods like
push(),pop(),splice(),sort(),reverse(), etc., are not available on aReadonlyArray. - Index Assignment: You cannot directly assign a new value to an index (e.g.,
arr[0] = 10;is disallowed). - Type Compatibility: A regular mutable array (
T[]) can be assigned to aReadonlyArray<T>. However, aReadonlyArray<T>cannot be assigned directly to aT[]without a type assertion, as it would lose the immutability guarantee. - Shallow Immutability: The
ReadonlyArrayitself is immutable, but if its elements are objects, those objects can still be mutated if they are not alsoreadonlyor immutable types.
const colors: readonly string[] = ["red", "green", "blue"];
// colors.push("yellow"); // Error: Property 'push' does not exist on type 'readonly string[]'.
// colors[0] = "scarlet"; // Error: Index signature in type 'readonly string[]' only permits reading.
const mutableColors: string[] = ["orange", "purple"];
const readOnlyColors: readonly string[] = mutableColors; // Allowed
// mutableColors = readOnlyColors; // Error: The type 'readonly string[]' is 'readonly' and cannot be assigned to the mutable type 'string[]'.
When to Use Readonly Arrays
- Function Parameters: When a function receives an array and you want to guarantee that the function will not modify the original array, declare the parameter as
ReadonlyArray<T>. - State Management: In patterns like Redux or React's state, using
ReadonlyArrayhelps enforce that state arrays are never mutated directly, encouraging the creation of new arrays for state updates. - API Responses: If you receive an array of data from an API that should be treated as fixed and unchangeable, defining it as
ReadonlyArrayprovides compile-time checks. - Data Structures: For any data structure that should remain constant after initialization.
function processData(data: ReadonlyArray<{ id: number; name: string }>): void {
// data.push({ id: 3, name: "Charlie" }); // Error
console.log("Processing", data.length, "items.");
// ... perform read-only operations ...
}
const userList = [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }];
processData(userList); // Pass a mutable array to a function expecting readonly
Readonly Tuples
Similar to ReadonlyArray, TypeScript also supports readonly tuples. A readonly tuple ensures that neither its length nor its element types can be changed after creation, offering type-safe immutability for fixed-length sequences.
type UserInfo = readonly [number, string, boolean];
const user1: UserInfo = [101, "John Doe", true];
// user1[0] = 102; // Error: Index signature in type 'readonly [number, string, boolean]' only permits reading.
Conclusion
Readonly arrays and tuples are invaluable TypeScript features for enhancing code reliability by enforcing immutability. By leveraging them, developers can prevent common bugs related to accidental data modification, leading to more predictable and maintainable applications.