🔒 Sự khác biệt giữa readonly và const trong TypeScript
Khi học TypeScript, một trong những nhầm lẫn thường gặp là:
👉 “Khi nào tôi nên sử dụng const và khi nào tôi nên sử dụng readonly?”
Nhìn qua, cả hai từ khóa có vẻ như có nghĩa giống nhau: "không thể thay đổi".
Nhưng thực tế, chúng hoạt động trong các ngữ cảnh khác nhau và phục vụ các mục đích khác nhau.
Trong bài viết này, chúng ta sẽ khám phá:
constvàreadonlythực sự có nghĩa là gì- Sự khác biệt chính với các ví dụ
- Các trường hợp sử dụng trong biến, đối tượng, mảng và lớp
- Một bảng tóm tắt để tham khảo nhanh
1. const trong TypeScript
Từ khóa const được sử dụng để khai báo các biến không thể được gán lại.
Ví dụ:
typescript
const x = 10;
// x = 20; ❌ Lỗi: không thể gán lại biến const
🔑 Quan trọng: const ngăn chặn việc gán lại liên kết, nhưng không ngăn chặn việc biến đổi đối tượng mà nó tham chiếu đến.
typescript
const user = { name: "Alice" };
user.name = "Bob"; // ✅ Cho phép
// user = { name: "Charlie" }; ❌ Không cho phép
Vì vậy, nếu một biến const giữ một đối tượng, bạn vẫn có thể cập nhật các thuộc tính của nó.
2. readonly trong TypeScript
Từ khóa readonly áp dụng cho các thuộc tính bên trong đối tượng, lớp và mảng.
Nó ngăn chặn việc sửa đổi thuộc tính đó, nhưng không ngăn chặn việc gán lại biến chứa đối tượng.
Ví dụ với Đối tượng:
typescript
type User = {
readonly name: string;
age: number;
};
let user: User = { name: "Alice", age: 25 };
user.age = 26; // ✅ Cho phép
// user.name = "Bob"; ❌ Lỗi: không thể gán cho thuộc tính readonly
Ví dụ với Lớp:
typescript
class Person {
readonly id: number; // thuộc tính không thay đổi
constructor(id: number) {
this.id = id;
}
}
const p = new Person(101);
// p.id = 202; ❌ Không cho phép
Ở đây, id không thay đổi sau khi được gán trong constructor.
3. So sánh const và readonly với Mảng
Đây là một mẹo phỏng vấn phổ biến! Hãy so sánh.
Mảng const
typescript
const numbers = [1, 2, 3];
numbers.push(4); // ✅ Cho phép
// numbers = [5, 6]; ❌ Không cho phép
- Bạn có thể sửa đổi nội dung.
- Bạn không thể gán lại biến đó.
Mảng readonly
typescript
const readonlyNumbers: readonly number[] = [1, 2, 3];
// readonlyNumbers.push(4); ❌ Không cho phép
// readonlyNumbers[0] = 100; ❌ Không cho phép
- Bạn không thể sửa đổi nội dung của mảng.
- Bạn vẫn có thể gán lại nếu nó không được khai báo bằng
const:
typescript
let arr: readonly number[] = [1, 2, 3];
arr = [4, 5, 6]; // ✅ Cho phép
4. Nơi áp dụng
const: Biến cấp cao, bên trong hàm, vòng lặp hoặc khối.readonly: Các thuộc tính đối tượng, thành viên lớp và mảng (như kiểu).
typescript
// biến const
const pi = 3.14;
// thuộc tính readonly
type Circle = {
readonly radius: number;
};
5. Thời gian biên dịch so với Thời gian chạy
Một sự khác biệt lớn khác là cách chúng tồn tại tại thời gian chạy:
const→ Tồn tại trong thời gian chạy JavaScript.readonly→ Chỉ có TypeScript, biến mất trong thời gian chạy.
Ví dụ:
typescript
const x = 10; // trong JS: const x = 10;
type User = { readonly name: string };
let u: User = { name: "Alice" };
// tại thời gian chạy → chỉ là một đối tượng thông thường
Vì vậy, readonly chỉ là một bảo đảm thời gian biên dịch.
6. Các trường hợp sử dụng thực tế
✅ Sử dụng const khi khai báo các biến mà bạn không muốn gán lại:
typescript
const API_URL = "https://api.example.com";
const MAX_RETRIES = 3;
✅ Sử dụng readonly khi mô hình hóa cấu trúc dữ liệu mà thuộc tính không nên thay đổi sau khi khởi tạo:
typescript
interface Config {
readonly apiKey: string;
readonly version: number;
}
const config: Config = {
apiKey: "abc123",
version: 1
};
// config.apiKey = "xyz789"; ❌ Không cho phép
✅ Kết hợp cả hai để tăng cường an toàn:
typescript
const users: readonly string[] = ["Alice", "Bob", "Charlie"];
// users.push("David"); ❌ Không cho phép
7. Tóm tắt sự khác biệt: Bảng tóm tắt
| Tính năng | const |
readonly |
|---|---|---|
| Áp dụng cho | Biến (liên kết) | Thuộc tính đối tượng, trường lớp, mảng |
| Ngăn chặn | Gán lại biến | Thay đổi thuộc tính/phần tử mảng |
| Phạm vi | Hàm, khối, biến toàn cục | Kiểu đối tượng, lớp, mảng |
| Tác động thời gian chạy | Tồn tại trong JavaScript (ES6 const) |
Chỉ có TypeScript (chỉ thời gian biên dịch) |
| Biến đổi đối tượng | Cho phép (thuộc tính có thể thay đổi) | Ngăn ngừa việc thay đổi thuộc tính |
| Biến đổi mảng | Cho phép (push, pop, v.v.) |
Ngăn chặn (readonly number[]) |
🔑 Suy nghĩ cuối cùng
- Sử dụng
constkhi bạn muốn khóa một liên kết biến. - Sử dụng
readonlykhi bạn muốn làm cho thuộc tính đối tượng hoặc mảng không thay đổi. - Kết hợp cả hai để có các mẫu không thay đổi mạnh mẽ trong TypeScript.
👉 Tóm lại:
const= bất biến cấp biếnreadonly= bất biến cấp thuộc tính