0
0
Lập trình
Sơn Tùng Lê
Sơn Tùng Lê103931498422911686980

Sự Khác Biệt Giữa Union Thông Thường và Union Phân Biệt Trong TypeScript

Đăng vào 7 tháng trước

• 4 phút đọc

Giới Thiệu

Trong lập trình React, việc quản lý trạng thái là rất quan trọng. Bạn thường xuyên phải xử lý nhiều trạng thái khác nhau như trạng thái của form (đang tải, thành công, lỗi), trạng thái của modal (mở, đóng) hay phản hồi từ API (dữ liệu hoặc lỗi). Một trong những khái niệm quan trọng mà bạn cần hiểu là sự khác biệt giữa union thông thường và union phân biệt trong TypeScript. Hiểu rõ điều này sẽ giúp bạn viết mã an toàn và dễ bảo trì hơn cho các component trong React.

Union Thông Thường Là Gì?

Union thông thường là kiểu dữ liệu có thể chứa nhiều giá trị hoặc kiểu giá trị khác nhau, nhưng TypeScript không liên kết thêm các trường dữ liệu với mỗi giá trị. Ví dụ:

typescript Copy
// Định nghĩa kiểu trạng thái

type Status = "loading" | "success" | "error";

function render(status: Status) {
  if (status === "success") {
    // ❌ Không thể đính kèm thông tin bổ sung như "data"
    return "Form đã được gửi!";
  }
  return "Chưa gửi";
}

Hạn Chế Của Union Thông Thường

  • Không có dữ liệu có cấu trúc cho mỗi trạng thái.
  • Không tự động thu hẹp kiểu cho các thuộc tính.
  • Chỉ phù hợp cho các cờ đơn giản.

Union Phân Biệt Là Gì?

Union phân biệt là một union của các đối tượng mà mỗi đối tượng có:

  • Một thuộc tính phân biệt (thường là một chuỗi hằng như status hoặc type).
  • Các trường dữ liệu bổ sung tùy chọn độc nhất cho từng nhánh.

Cách TypeScript Thu Hẹp Kiểu

typescript Copy
// Định nghĩa kiểu trạng thái form

type FormState =
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function renderForm(state: FormState) {
  if (state.status === "loading") return <p>Đang tải...</p>;
  if (state.status === "success") return <p>Đã gửi: {state.data}</p>;
  if (state.status === "error") return <p>Lỗi: {state.message}</p>;
}
  • TypeScript tự động thu hẹp kiểu của state dựa trên thuộc tính phân biệt (status).
  • Mỗi nhánh chỉ có quyền truy cập vào các trường liên quan (data, message).

So Sánh Union Thông Thường và Union Phân Biệt

Không Có Union Phân Biệt

typescript Copy
// Không có union phân biệt

type FormState = "loading" | "success" | "error";

function renderForm(state: FormState) {
  if (state === "success") {
    // ❌ Không thể đính kèm thông tin bổ sung như data
    return "Form đã được gửi!";
  }
}

Có Union Phân Biệt

typescript Copy
// Với union phân biệt

type FormState =
  | { status: "loading" }
  | { status: "success"; data: string }
  | { status: "error"; message: string };

function renderForm(state: FormState) {
  if (state.status === "success") {
    // ✅ TypeScript biết 'data' tồn tại
    return `Form đã được gửi với: ${state.data}`;
  }
}

Các Trường Hợp Sử Dụng Thực Tế Trong React

Ví Dụ Về Trạng Thái Form

typescript Copy
// Định nghĩa trạng thái cho form

type FormState =
  | { status: "idle" }
  | { status: "submitting" }
  | { status: "success"; result: string }
  | { status: "error"; message: string };

function Form({ state }: { state: FormState }) {
  switch (state.status) {
    case "idle": return <button>Gửi</button>;
    case "submitting": return <p>Đang gửi...</p>;
    case "success": return <p>{state.result}</p>;
    case "error": return <p>{state.message}</p>;
  }
}

Ví Dụ Về Modal

typescript Copy
// Định nghĩa trạng thái cho modal

type ModalState =
  | { open: true; content: string }
  | { open: false };

function Modal({ state }: { state: ModalState }) {
  if (!state.open) return null;
  return <div>{state.content}</div>;
}

Kết Luận

Union thông thường có thể đủ cho các cờ đơn giản, nhưng chúng không thể mang theo dữ liệu cho từng trường hợp. Ngược lại, union phân biệt cho phép TypeScript biết chính xác các trường nào tồn tại cho từng trường hợp, làm cho các component trở nên an toàn hơn. Đối với các ứng dụng React, luôn ưu tiên sử dụng union phân biệt cho trạng thái component, phản hồi từ API và các thuộc tính loại trừ lẫn nhau.

Thực Hành Tốt Nhất

  • Luôn sử dụng union phân biệt khi thiết kế trạng thái cho các component.
  • Đảm bảo rằng các thuộc tính phân biệt rõ ràng và dễ hiểu.

Các Cạm Bẫy Thông Thường

  • Không sử dụng union thông thường cho các trường hợp cần dữ liệu có cấu trúc.
  • Không quên kiểm tra kỹ các thuộc tính trong mỗi nhánh.

Câu Hỏi Thường Gặp (FAQ)

1. Union phân biệt có thể được sử dụng trong các tình huống nào?
Union phân biệt rất hữu ích trong các tình huống mà bạn cần xác định trạng thái của một component hoặc phản hồi từ API.

2. Có cách nào khác để quản lý trạng thái trong React không?
Có, bạn có thể sử dụng các thư viện như Redux hoặc Context API để quản lý trạng thái, nhưng union phân biệt thường mang lại lợi ích rõ ràng hơn khi bạn muốn làm rõ cấu trúc dữ liệu.

3. Tại sao TypeScript lại tự động thu hẹp kiểu?
TypeScript sử dụng thuộc tính phân biệt để xác định kiểu dữ liệu chính xác, giúp giảm thiểu lỗi và tăng cường bảo trì.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào