Union cho phép một giá trị thuộc một trong nhiều kiểu. Narrowing là kỹ thuật thu hẹp kiểu để dùng an toàn. Đây là kỹ năng quan trọng nhất khi viết TypeScript thực tế.
- Khai báo và dùng union type
- Thu hẹp kiểu bằng typeof, in, instanceof, so sánh
- Thiết kế discriminated union
- Kiểm tra vét cạn với never
- Union (|)
- Giá trị thuộc một trong các kiểu.
- Narrowing
- TS tự thu hẹp kiểu sau câu lệnh kiểm tra.
- Discriminant
- Thuộc tính chung có giá trị literal khác nhau để phân biệt nhánh.
- Exhaustive check
- Đảm bảo đã xử lý mọi trường hợp.
Khái niệm và lý thuyết
Với union string | number, bạn chỉ được dùng các thao tác chung của cả hai kiểu. Muốn dùng phương thức riêng, phải thu hẹp. TS phân tích luồng điều khiển (control flow analysis): sau if (typeof x === "string"), trong nhánh đó x là string, ở nhánh else x là number.
Discriminated union là mẫu thiết kế cốt lõi: mỗi biến thể có thuộc tính chung (ví dụ kind) mang giá trị literal riêng. Mẫu này mô hình hóa trạng thái (đang tải, thành công, lỗi) rất chính xác, loại bỏ các tổ hợp trạng thái vô nghĩa.
Các cách thu hẹp
| Cách | Ví dụ | Dùng cho |
|---|---|---|
| typeof | typeof x === "string" | Kiểu nguyên thủy |
| Truthiness | if (x) | Loại null/undefined/"" |
| in | "bay" in con | Phân biệt object theo thuộc tính |
| instanceof | e instanceof Date | Đối tượng tạo từ lớp |
| So sánh | x.kind === "loi" | Discriminated union |
function inId(id: string | number) {
if (typeof id === "string") console.log(id.toUpperCase());
else console.log(id.toFixed(0));
}Discriminated union
type KetQua =
| { trangThai: "dang-tai" }
| { trangThai: "thanh-cong"; duLieu: string[] }
| { trangThai: "loi"; thongBao: string };
function hienThi(kq: KetQua): string {
switch (kq.trangThai) {
case "dang-tai": return "Đang tải...";
case "thanh-cong": return kq.duLieu.join(", ");
case "loi": return "Lỗi: " + kq.thongBao;
default: {
const _vetCan: never = kq; // báo lỗi nếu quên một nhánh
return _vetCan;
}
}
}Khi thêm biến thể mới vào KetQua, dòng never sẽ báo lỗi ở mọi chỗ chưa xử lý: trình biên dịch nhắc việc thay bạn.
Mô hình ThanhToan gồm tiền mặt (số tiền), chuyển khoản (số tiền, mã giao dịch), ví điện tử (số tiền, tên ví). Hàm tính phí xử lý theo từng loại dùng switch và kiểm tra vét cạn.
Đặt tên discriminant thống nhất trong dự án (type, kind hoặc status) để đồng đội dễ nhận ra mẫu.
Narrowing bị mất trong callback nếu biến có thể bị gán lại (let). Gán vào một const trước khi dùng trong callback.
- Viết hàm
doDai(x: string | string[])trả về số ký tự hoặc số phần tử. - Mô hình hình học
Hinh(tròn, chữ nhật, tam giác) và hàm tính diện tích. - Thêm biến thể “vuông” và quan sát lỗi never.
- Mô hình trạng thái gửi biểu mẫu: chưa gửi, đang gửi, đã gửi, lỗi.
- Union mô tả “một trong nhiều”.
- Thu hẹp bằng typeof, in, instanceof, so sánh.
- Discriminated union mô hình hóa trạng thái chính xác.
- never giúp kiểm tra vét cạn.