Đội ngũ TypeScript đã phát hành một flag trình biên dịch mới trong bản 6.0 – --noPropertyAccessFromIndexSignature. Khi được bật, trình biên dịch sẽ từ chối việc truy cập thuộc tính bằng ký hiệu dấu chấm (dot-notation) đối với các thuộc tính đến từ một index signature, buộc các nhà phát triển phải sử dụng ký hiệu ngoặc vuông (bracket notation) và làm lộ diện các giá trị undefined tiềm ẩn ngay tại thời điểm biên dịch thay vì khi chạy thực tế (production).
Tại sao flag này lại quan trọng
Trong JavaScript, các đối tượng thường đóng vai trò như các từ điển (dictionaries), và TypeScript cho phép bạn định nghĩa kiểu cho các cấu trúc như vậy bằng một index signature, ví dụ: Record<string, T>. Ngôn ngữ này coi obj.key và obj["key"] là có thể thay thế cho nhau, vì vậy trình biên dịch mặc định rằng thuộc tính đó tồn tại ngay cả khi khóa (key) chỉ được biết tại thời điểm runtime. Giả định ngầm định đó chính là nguồn cơn của nhiều lỗi crash: mã nguồn truy cập obj.missingProp vẫn biên dịch bình thường, chạy được, nhưng sau đó sẽ văng lỗi vì giá trị là undefined.
Ký hiệu dấu chấm mang một sự đảm bảo ngầm định – nó báo cho người đọc và trình kiểm tra kiểu (type checker) biết rằng thuộc tính đó chắc chắn hiện diện. Ngược lại, ký hiệu ngoặc vuông báo hiệu sự không chắc chắn – khóa có thể bị thiếu và kết quả có thể là undefined. --noPropertyAccessFromIndexSignature thực thi sự phân biệt về mặt hình ảnh và ngữ nghĩa đó, chuyển đổi một nhóm các lỗi runtime thành các cảnh báo chẩn đoán tại thời điểm biên dịch.
Cách thức hoạt động của flag
Khi flag được bật, bất kỳ biểu thức nào truy cập thuộc tính thông qua một index signature bằng ký hiệu dấu chấm đều sẽ bị đánh dấu là lỗi. Mã nguồn phải được viết lại để sử dụng ngoặc vuông:
// Before
const name = userData.name; // OK even if "name" is not in the index
// After enabling the flag
const name = userData["name"]; // Error unless brackets are used
Sau đó, trình biên dịch sẽ áp dụng các quy tắc xử lý undefined tương tự như những gì nó đã sử dụng cho việc truy cập bằng ngoặc vuông. Nếu --noUncheckedIndexedAccess cũng được bật, kiểu của userData["name"] sẽ trở thành T | undefined, buộc nhà phát triển phải kiểm tra trường hợp bị thiếu.
Các bước chuyển đổi thực tế
Bật flag trong
tsconfig.json:{ "compilerOptions": { "noPropertyAccessFromIndexSignature": true } }Chạy trình kiểm tra kiểu. Tất cả các truy cập bằng dấu chấm vào các khóa của index signature sẽ xuất hiện dưới dạng lỗi.
Thay thế dấu chấm bằng ngoặc vuông. Việc thay đổi này mang tính cơ học; nó không ảnh hưởng đến hiệu suất runtime.
Xử lý các kiểu
undefinedphát sinh. Thêm nullish coalescing, optional chaining hoặc các kiểm tra tường minh ở những nơi cần thiết.Cân nhắc kết hợp với
--noUncheckedIndexedAccessđể có được lưới an toàn mạnh mẽ nhất. Cùng với nhau, chúng đảm bảo rằng bất kỳ truy cập kiểu từ điển nào cũng được coi là có khả năng bị thiếu.
Khi nào nên giữ các thuộc tính tường minh
Nếu một trường là một phần của hợp đồng API ổn định, hãy khai báo nó như một thuộc tính tường minh thay vì dựa vào một index signature. Các thuộc tính tường minh tiếp tục cho phép sử dụng ký hiệu dấu chấm, duy trì sự đảm bảo rằng trường đó sẽ luôn hiện diện (trong phạm vi hệ thống kiểu có thể xác minh). Hãy dành index signature cho các dữ liệu thực sự động, nơi các khóa không được biết trước.
Quan điểm ngược lại: tăng độ rườm rà
Một số đội ngũ có thể thấy việc thêm các dấu ngoặc vuông gây rườm rà, đặc biệt là trong các mã nguồn sử dụng nhiều đối tượng linh hoạt. Flag này buộc một kỷ luật nghiêm ngặt hơn, điều có thể yêu cầu một đợt tái cấu trúc (refactor) đáng kể cho các dự án cũ (legacy). Đối với những trường hợp đó, flag có thể được áp dụng dần dần, có lẽ chỉ giới hạn trong các module mới, trong khi toàn bộ mã nguồn sẽ áp dụng mô hình này theo thời gian.
Những gì cần theo dõi tiếp theo
Flag này là một phần trong nỗ lực rộng lớn hơn của TypeScript 6.0 hướng tới tính an toàn kiểu nghiêm ngặt hơn. Các bản phát hành trong tương lai có thể giới thiệu thêm các kiểm tra xung quanh object spread, optional chaining hoặc việc sử dụng any được suy luận. Việc theo dõi lộ trình (roadmap) của TypeScript sẽ giúp các đội ngũ quyết định khi nào nên áp dụng bộ tính năng an toàn tiếp theo mà không làm gián đoạn lịch trình bàn giao.
Bài học rút ra: Việc bật --noPropertyAccessFromIndexSignature giúp làm rõ sự phân biệt giữa “thuộc tính này được đảm bảo” và “thuộc tính này có thể bị thiếu” ngay trong mã nguồn, giúp bắt được cả một nhóm lỗi trước khi chúng đến môi trường production. Việc chuyển đổi một lỗi runtime âm thầm thành một lỗi tại thời điểm biên dịch là một thay đổi nhỏ nhưng mang lại tác động cực kỳ lớn đến độ tin cậy.
