Giới thiệu về readonly trong TypeScript
Khi làm việc với các đối tượng trong TypeScript, việc ngăn chặn những thay đổi không mong muốn đến các thuộc tính nhất định là rất quan trọng. Modifiers readonly của TypeScript giúp bạn khóa các thuộc tính để chúng không thể được gán lại sau khi đã được tạo ra. Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết về cách sử dụng readonly, từ cú pháp cơ bản đến các lưu ý và ví dụ thực tế.
Mục lục
- Modifier
readonlytrong Interface hoặc Type Alias - Kiểu Utility
Readonly<T> - Khi nào nên sử dụng
readonly - Những điểm chính cần nhớ
- Các thực tiễn tốt nhất
- Những cạm bẫy thường gặp
- Mẹo hiệu suất
- Giải quyết sự cố
- Câu hỏi thường gặp
Modifier readonly trong Interface hoặc Type Alias
Bạn có thể thêm readonly trực tiếp vào từng thuộc tính:
typescript
// Định nghĩa kiểu User với thuộc tính readonly
type User = {
readonly name: string;
readonly age: number;
};
namevàageđều là đọc chỉ.- Một khi đối tượng
Userđược tạo ra, các thuộc tính này không thể được gán lại.
Ví dụ:
typescript
const user: User = {
name: "Safal",
age: 10,
};
user.age = 12; // ❌ Lỗi: Không thể gán cho 'age' vì nó là thuộc tính đọc chỉ
Trình biên dịch TypeScript sẽ kiểm tra tính bất biến này ngay trong quá trình biên dịch. (Tại thời điểm chạy, nó vẫn là một đối tượng JavaScript bình thường, nhưng TypeScript sẽ ngăn bạn viết mã có thể làm biến đổi nó.)
Kiểu Utility Readonly<T>
Thay vì viết readonly cho từng thuộc tính, TypeScript cung cấp một kiểu utility tích hợp:
typescript
// Định nghĩa kiểu User1
type User1 = {
name: string;
age: number;
};
const user1: Readonly<User1> = {
name: "Safal",
age: 10,
};
Ở đây, Readonly<User1> tạo ra một kiểu mới giống hệt như User1, nhưng tất cả các thuộc tính đều được đánh dấu là readonly.
Nó tương đương với:
typescript
// Định nghĩa kiểu ReadonlyUser1
type ReadonlyUser1 = {
readonly name: string;
readonly age: number;
};
Bất kỳ nỗ lực nào để gán lại:
typescript
user1.name = "New Name"; // ❌ Lỗi: Không thể gán cho 'name' vì nó là thuộc tính đọc chỉ
Khi nào nên sử dụng readonly
- Mô hình dữ liệu bất biến: Ngăn ngừa các thay đổi không mong muốn trong các đối tượng cấu hình hoặc trạng thái Redux.
- Ranh giới API: Khi cung cấp dữ liệu cho các phần khác của ứng dụng mà không nên bị thay đổi.
- Mô hình lập trình hàm: Thực thi tính bất biến theo thiết kế.
Những điểm chính cần nhớ
- Chỉ kiểm tra tại thời điểm biên dịch:
readonlyđược thực thi bởi bộ kiểm tra kiểu của TypeScript. JavaScript không tự động làm đông lạnh đối tượng.
- Nếu bạn cần tính bất biến tại thời điểm chạy, bạn cũng có thể sử dụng
Object.freeze().
- Cấp độ nông:
readonlychỉ áp dụng cho các thuộc tính cấp cao nhất, không áp dụng cho các đối tượng lồng nhau.
Ví dụ:
typescript
// Định nghĩa kiểu Nested
type Nested = {
readonly info: { value: number };
};
const x: Nested = { info: { value: 1 } };
x.info.value = 2; // ✅ Cho phép, vì 'value' không được đánh dấu là readonly
Các thực tiễn tốt nhất
- Sử dụng
readonlycho các thuộc tính quan trọng: Đảm bảo rằng các thuộc tính không bị thay đổi bởi những phần khác trong mã. - Kết hợp với các kiểu khác: Sử dụng
readonlycùng với các kiểu khác để tạo ra các cấu trúc dữ liệu an toàn và dễ bảo trì.
Những cạm bẫy thường gặp
- Quên thêm
readonlyvào các thuộc tính quan trọng: Điều này có thể dẫn đến việc các thuộc tính có thể bị thay đổi không mong muốn. - Không hiểu rõ cách hoạt động của
readonly: Như đã đề cập ở trên,readonlychỉ kiểm tra tại thời điểm biên dịch.
Mẹo hiệu suất
- Sử dụng
Readonly<T>cho các kiểu lớn: Giúp giảm thiểu mã lặp lại và tăng khả năng bảo trì. - Kiểm tra hiệu suất: Theo dõi hiệu suất ứng dụng khi sử dụng các đối tượng không thay đổi để đảm bảo hiệu suất không bị ảnh hưởng.
Giải quyết sự cố
- Lỗi khi gán lại thuộc tính: Nếu bạn gặp lỗi khi cố gắng gán lại một thuộc tính đọc chỉ, hãy kiểm tra xem thuộc tính đó có được đánh dấu là
readonlyhay không. - Tìm hiểu về
Object.freeze(): Nếu bạn cần tính bất biến tại thời điểm chạy, hãy tìm hiểu về cách sử dụngObject.freeze().
Câu hỏi thường gặp
1. readonly có khác gì so với const?
readonly chỉ áp dụng cho thuộc tính của một đối tượng, trong khi const áp dụng cho biến không thể gán lại.
2. Làm thế nào để sử dụng readonly với các kiểu phức tạp?
Bạn có thể kết hợp readonly với các kiểu phức tạp như array hoặc các đối tượng lồng nhau để đảm bảo tính bất biến.
3. Có thể sử dụng readonly trong các lớp không?
Có, bạn có thể sử dụng readonly trong các lớp để đánh dấu các thuộc tính không thể thay đổi.
Kết luận
Sử dụng readonly khi bạn muốn TypeScript đảm bảo tính bất biến cho các thuộc tính của đối tượng. Hãy thêm readonly trực tiếp vào các thuộc tính cụ thể để kiểm soát chính xác hơn, hoặc sử dụng Readonly<T> để khóa toàn bộ kiểu một cách nhanh chóng. Điều này giúp giữ cho cấu trúc dữ liệu của bạn trở nên dự đoán được và bảo vệ chống lại những thay đổi không mong muốn trong các mã nguồn lớn.