This chapter focuses on the readonly modifier in TypeScript, a feature that restricts properties from being reassigned after initialization. The readonly modifier ensures immutability for class properties and type declarations, enhancing type safety and reducing unintended changes.
Chapter Goal
- To understand what the readonly modifier is and its purpose in TypeScript.
- To learn how to use the readonly modifier for properties and types.
- To explore practical applications of the readonly modifier for enforcing immutability.
Key Characteristics for TypeScript Readonly Modifier
- Immutability: Ensures that a property cannot be reassigned after it is initialized.
- Type Safety: Prevents accidental modification of constant values.
- Declarative Syntax: Simple and clear syntax using the readonly keyword.
- Class Properties: Often used for defining immutable class members.
- Interfaces and Types: Applicable to object and array types for immutability.
Basic Rules for TypeScript Readonly Modifier
- Use readonly to prevent reassignment of properties after initialization.
- Apply readonly to class properties, interfaces, and type declarations.
- Initialize readonly properties either inline or in the constructor.
- Combine readonly with const for complete immutability.
- Avoid using readonly for properties that require updates.
Best Practices
- Use readonly for properties that represent constants or fixed values.
- Document the purpose of readonly properties to enhance code clarity.
- Combine readonly with TypeScript’s utility types like Readonly<T> for deep immutability.
- Avoid using readonly for mutable data or frequently updated values.
- Regularly review readonly declarations to ensure consistency with the code’s intent.
Syntax Table
Serial No | Component | Syntax Example | Description |
1 | Basic Readonly Property | readonly id: number; | Declares a read-only property in a class. |
2 | Inline Initialization | readonly name: string = ‘Alice’; | Initializes a readonly property inline. |
3 | Constructor Assignment | readonly balance: number; constructor(balance: number) { this.balance = balance; } | Assigns a readonly property in the constructor. |
4 | Readonly Array | readonly numbers: number[] = [1, 2, 3]; | Declares a readonly array. |
5 | Readonly Utility Type | Readonly<T> | Makes all properties of T read-only. |
Syntax Explanation
1. Basic Readonly Property
What is a Basic Readonly Property
A property that cannot be reassigned after it is initialized.
Syntax
class Product {
readonly id: string;
constructor(id: string) {
this.id = id;
}
}
Detailed Explanation
- The id property is marked as readonly and can only be assigned in the constructor.
- Attempts to reassign the id property will result in a compile-time error.
Example
const product = new Product(‘P123’);
console.log(product.id); // Output: P123
// product.id = ‘P124’; // Error: Cannot assign to ‘id’ because it is a read-only property.
Output
P123
Notes
- Use readonly for properties that represent fixed identifiers or constants.
Warnings
- Ensure that readonly properties are initialized either inline or in the constructor.
2. Inline Initialization
What is Inline Initialization
Assigning a value to a readonly property directly during its declaration.
Syntax
class User {
readonly name: string = ‘Default User’;
}
Detailed Explanation
- Inline initialization sets the readonly property at the time of declaration.
- This approach is useful for properties with default values that rarely change.
Example
const user = new User();
console.log(user.name); // Output: Default User
// user.name = ‘Admin’; // Error: Cannot assign to ‘name’ because it is a read-only property.
Output
Default User
Notes
- Inline initialization simplifies the class constructor for fixed properties.
Warnings
- Avoid inline initialization for properties that require dynamic assignment.
3. Constructor Assignment
What is Constructor Assignment
Initializing a readonly property within the class constructor.
Syntax
class Account {
readonly balance: number;
constructor(balance: number) {
this.balance = balance;
}
}
Detailed Explanation
- Constructor assignment provides flexibility to initialize readonly properties with dynamic values.
- This approach is commonly used for properties dependent on constructor arguments.
Example
const account = new Account(1000);
console.log(account.balance); // Output: 1000
// account.balance = 2000; // Error: Cannot assign to ‘balance’ because it is a read-only property.
Output
1000
Notes
- Constructor assignment is ideal for properties initialized with runtime values.
Warnings
- Ensure that all readonly properties are assigned within the constructor.
4. Readonly Array
What is a Readonly Array
An array declared with the readonly modifier, preventing reassignment of the array reference.
Syntax
class Data {
readonly values: number[] = [1, 2, 3];
}
Detailed Explanation
- The array reference is immutable, but the array contents can still be modified.
- Use TypeScript’s ReadonlyArray<T> for true immutability of array contents.
Example
const data = new Data();
console.log(data.values); // Output: [1, 2, 3]
// data.values = [4, 5, 6]; // Error: Cannot assign to ‘values’ because it is a read-only property.
data.values.push(4); // This is allowed.
console.log(data.values); // Output: [1, 2, 3, 4]
Output
[1, 2, 3]
[1, 2, 3, 4]
Notes
- Use ReadonlyArray<T> for strict immutability if modifying contents should be restricted.
Warnings
- Remember that the readonly modifier applies only to the reference, not the array elements.
5. Readonly Utility Type
What is the Readonly Utility Type
A TypeScript utility type that makes all properties of a type read-only.
Syntax
type ReadonlyObject = Readonly<{ name: string; age: number }>;
const obj: ReadonlyObject = { name: ‘Alice’, age: 25 };
Detailed Explanation
- The Readonly utility type applies the readonly modifier to every property of a type.
- This ensures deep immutability for object structures.
Example
console.log(obj.name); // Output: Alice
// obj.name = ‘Bob’; // Error: Cannot assign to ‘name’ because it is a read-only property.
Output
Alice
Notes
- Combine Readonly<T> with nested types for comprehensive immutability.
Warnings
- Avoid overusing Readonly for types that require frequent updates.
Real-Life Project
Project Name
Immutable Configuration Settings
Project Goal
Demonstrates how to use the readonly modifier to define immutable configuration settings for an application.
Code for This Project
class Config {
readonly appName: string;
readonly version: string;
readonly features: ReadonlyArray<string>;
constructor(appName: string, version: string, features: string[]) {
this.appName = appName;
this.version = version;
this.features = features;
}
}
const config = new Config('MyApp', '1.0.0', ['login', 'dashboard']);
console.log(config.appName); // Output: MyApp
console.log(config.features); // Output: ['login', 'dashboard']
// config.appName = 'NewApp'; // Error: Cannot assign to 'appName' because it is a read-only property.
// config.features.push('analytics'); // Error if using `ReadonlyArray`.
Save and Run
- Save the code in your development environment, such as Visual Studio Code, ensuring the file is named config.ts.
- Compile the TypeScript code into JavaScript using the command tsc config.ts in your terminal.
- Execute the resulting JavaScript file using the command node config.js.
Expected Output
MyApp
[‘login’, ‘dashboard’]