Họ đang đo gì
Bạn dùng TypeScript để bắt lỗi hay dùng nó để im lặng trình biên dịch.
Trả lời ngắn~30 giây
any tắt hoàn toàn kiểm tra kiểu: gán được cho bất cứ đâu, gọi phương thức gì cũng không ai cản. unknown nhận được mọi giá trị nhưng không cho bạn làm gì với nó cho tới khi thu hẹp kiểu — đó chính là mục đích. as không chuyển đổi gì cả, nó chỉ bảo trình biên dịch im lặng; nếu bạn đoán sai thì lỗi rơi xuống runtime, đúng chỗ mà TypeScript lẽ ra phải bảo vệ bạn.
Giải thích sâu
Chỗ nguy hiểm nhất của any là nó LAN. Một any từ thư viện bên ngoài chảy qua bốn lớp hàm, và mọi chỗ nó đi qua đều mất kiểm tra kiểu mà không có cảnh báo nào. Bật noImplicitAny chỉ chặn any ngầm; any tường minh thì cần lint rule riêng. Trong khi đó unknown dừng lại ngay tại điểm sử dụng đầu tiên, nên nó là kiểu đúng cho mọi thứ đi vào từ bên ngoài: JSON.parse, body của request, catch (e).
Về as, điều cần nói là TypeScript biến mất hoàn toàn khi biên dịch. Không có kiểm tra lúc chạy, không có ép kiểu, không có gì. const user = data as User với data là JSON từ mạng chỉ là một lời hứa mà không ai kiểm chứng — và ngày API đổi tên trường, bạn nhận undefined ở tận đâu đó trong giao diện. Cách đúng là kiểm tra ở biên bằng Zod hoặc một type guard tự viết, sau đó bên trong hệ thống bạn mới được tin vào kiểu.
Có một ngoại lệ hợp lý cho as: khi bạn biết nhiều hơn trình biên dịch một cách thật sự, ví dụ sau khi đã kiểm tra bằng một cách mà TypeScript không suy luận được. Lúc đó nên viết kèm bình luận nói vì sao bạn chắc. Một as có lý do giải thích được là kỹ thuật; một as để cho hết đỏ là nợ kỹ thuật.
function handleAny(x: any) {
x.foo.bar(); // biên dịch được, nổ lúc chạy
}
function handleUnknown(x: unknown) {
x.foo.bar(); // lỗi biên dịch — đúng như mong muốn
if (typeof x === 'object' && x !== null && 'foo' in x) {
// ở đây x đã được thu hẹp, dùng an toàn
}
}
// catch luôn là unknown từ TS 4.4 (useUnknownInCatchVariables)
try { risky(); } catch (e) {
const message = e instanceof Error ? e.message : String(e);
}Câu hỏi tiếp theo họ sẽ hỏi
?never dùng khi nào?
Cho thứ không bao giờ xảy ra: hàm không bao giờ return, hoặc nhánh không thể tới. Ứng dụng hữu ích nhất là kiểm tra vét cạn — gán biến vào never trong nhánh default của switch, để khi ai đó thêm một biến thể mới vào union thì build đỏ ngay.
?Kiểu của TypeScript có tồn tại lúc chạy không?
Không. Chúng bị xoá hoàn toàn. Đó là lý do mọi dữ liệu từ bên ngoài phải được kiểm tra thật ở biên, và cũng là lý do instanceof hoạt động còn “kiểm tra interface” thì không.
Trả lời thế này là mất điểm
- Dùng
anyđể “sửa nhanh” rồi để đó. Nó không sửa gì, chỉ dời lỗi sang runtime. - Nghĩ
ascó kiểm tra lúc chạy. Đây là hiểu nhầm gây ra rất nhiều lỗi production.