TypeScript - Never: Hiểu về Kiểu Bottom

Xin chào, những người học lập trình!I Hôm nay, chúng ta sẽ cùng tìm hiểu một trong những kiểu bí ẩn của TypeScript: kiểu never. Đừng lo lắng nếu bạn mới bắt đầu học lập trình - Tôi sẽ hướng dẫn bạn từng bước, giống như tôi đã làm cho hàng trăm học sinh trong những năm dạy học của mình. Vậy, hãy lấy饮料 yêu thích của bạn, và cùng bắt đầu hành trình thú vị vào thế giới của TypeScript!

TypeScript - Never

Kiểu never là gì?

Kiểu never trong TypeScript thường được gọi là "kiểu bottom" hoặc "kiểu rỗng". Nó đại diện cho một kiểu mà không bao giờ xảy ra. Bây giờ, bạn có thể đang nghĩ, "Tại sao chúng ta lại cần một kiểu không bao giờ xảy ra?" Well, những người bạn tò mò, nó hữu ích hơn bạn tưởng!

Khi nào sử dụng never?

  1. Để đại diện cho các tình huống không thể xảy ra
  2. Để xử lý các kiểm tra toàn diện
  3. Trong các hàm không bao giờ trả về

Hãy cùng xem một số ví dụ để làm rõ hơn các khái niệm này.

Ví dụ 1: Đại diện cho các tình huống không thể xảy ra

function throwError(message: string): never {
throw new Error(message);
}

let result = throwError("Oops! Something went wrong!");
console.log(result); // Dòng này sẽ không bao giờ được Reached

Trong ví dụ này, hàm throwError đảm bảo rằng sẽ ném ra một lỗi và không bao giờ trả về bình thường. Do đó, kiểu trả về của nó là never.

Hãy nghĩ như này: Nếu bạn đang nướng bánh và công thức nói "nướng đến khi nào không còn", bạn biết rằng bánh không ra khỏi lò!

Ví dụ 2: Kiểm tra toàn diện

type Shape = "circle" | "square" | "triangle";

function getArea(shape: Shape): number {
switch (shape) {
case "circle":
return Math.PI * Math.pow(5, 2);
case "square":
return 10 * 10;
case "triangle":
return (10 * 5) / 2;
default:
const _exhaustiveCheck: never = shape;
return _exhaustiveCheck;
}
}

Ở đây, never giúp chúng ta đảm bảo rằng chúng ta đã bao gồm tất cả các hình dạng có thể. Nếu chúng ta thêm một hình dạng mới vào kiểu Shape nhưng quên thêm một trường hợp cho nó trong getArea, TypeScript sẽ cho chúng ta một lỗi. Nó giống như có một trợ lý hữu ích nhắc nhở bạn khi bạn quên điều gì!

Ví dụ 3: Các hàm không bao giờ trả về

function infiniteLoop(): never {
while (true) {
console.log("This loop never ends!");
}
}

Hàm này sẽ chạy mãi mãi (hoặc cho đến khi máy tính của bạn hết bộ nhớ). Vì nó không bao giờ kết thúc thực thi, kiểu trả về của nó là never. Nó giống như nói với bạn bè rằng bạn sẽ ngừng nói "never" - họ biết rằng họ sẽ có một cuộc trò chuyện dài!

Kiểu never vs. void

Bây giờ, bạn có thể đang tự hỏi, "Kiểu never khác gì với void?" Câu hỏi tuyệt vời! Hãy cùng phân tích.

void

Kiểu void được sử dụng khi một hàm không trả về bất kỳ giá trị nào, nhưng nó vẫn hoàn thành việc thực thi.

function logMessage(message: string): void {
console.log(message);
}

logMessage("Hello, TypeScript!"); // Hàm này trả về `undefined`

never

Kiểu never, mặt khác, được sử dụng khi một hàm không bao giờ hoàn thành việc thực thi hoặc luôn ném ra một lỗi.

function failwithError(message: string): never {
throw new Error(message);
}

failwithError("This function never returns!");

Hãy nghĩ như này: void giống như đi đến một cửa hàng và trở về tay không, trong khi never giống như bắt đầu một hành trình không có điểm đến - bạn không bao giờ trở về!

Các ứng dụng thực tế của never

Hãy cùng xem một số ví dụ thực tế hơn nơi never có thể hữu ích.

Ví dụ 4: Bảo vệ kiểu

type Square = { kind: "square", size: number };
type Circle = { kind: "circle", radius: number };
type Shape = Square | Circle;

function assertNever(x: never): never {
throw new Error("Unexpected object: " + x);
}

function getArea(shape: Shape) {
switch (shape.kind) {
case "square": return shape.size * shape.size;
case "circle": return Math.PI * shape.radius ** 2;
default: return assertNever(shape); // Lỗi nếu shape không phải Square hoặc Circle
}
}

Trong ví dụ này, assertNever giúp chúng ta bắt được bất kỳ trường hợp nào chúng ta có thể bỏ sót. Nó giống như có một mạng an toàn khi bạn đang học cách ném 类型!

Ví dụ 5: Phát hiện mã không thểReached

function neverReaches(): never {
while (true) {
// Một số thao tác
}
console.log("This line will never be reached");  // Lỗi TypeScript
}

TypeScript thông minh đủ để biết rằng câu lệnh console.log sẽ không bao giờ đượcReached, và nó sẽ cho bạn một lỗi. Nó giống như có một GPS告诉 bạn khi bạn đang cố gắng lái xe đến một nơi không tồn tại!

Phương thức và thuộc tính của never

Bây giờ, bạn có thể đang tự hỏi nếu never có bất kỳ phương thức hoặc thuộc tính nào. Sự thật là, never không có bất kỳ phương thức hoặc thuộc tính nào của riêng nó vì nó đại diện cho một kiểu mà không bao giờ xảy ra. Tuy nhiên, nó vẫn là một phần quan trọng của hệ thống kiểu TypeScript.

Dưới đây là bảng tóm tắt những gì bạn có thể (hoặc không thể) làm với never:

Thao tác Kết quả Giải thích
Gán cho never ✅ Cho phép Bất kỳ kiểu nào cũng có thể được gán cho never
Gán never cho các kiểu khác ❌ Không cho phép never không thể được gán cho bất kỳ kiểu nào khác
Gọi phương thức trên never ❌ Không cho phép never không bao giờ xảy ra, bạn không thể gọi phương thức trên nó
Sử dụng never trong các union ✅ Cho phép nhưng không có tác dụng never bị bỏ qua trong các kiểu union
Sử dụng never trong các intersection ✅ Cho phép và kết quả là never Bất kỳ kiểu nào giao với never sẽ kết quả là never

Kết luận

Và đây là nó, các học trò yêu quý của tôi! Chúng ta đã cùng nhau hành trình qua vùng đất của never, khám phá từng ngóc ngách. Nhớ rằng, never giống như người bạn luôn hủy bỏ kế hoạch - họ không bao giờ xuất hiện, nhưng họ vẫn quan trọng để nhớ đến!

Hiểu never có thể seem khó khăn ban đầu, nhưng với sự luyện tập, bạn sẽ thấy nó là một công cụ vô giá trong bộ công cụ TypeScript của bạn. Nó giúp mã của bạn trở nên vững chắc hơn, bắt được các lỗi tiềm ẩn và thậm chí làm bạn suy nghĩ sâu hơn về hành vi của hàm của bạn.

Tiếp tục lập trình, tiếp tục học hỏi, và đừng bao giờ nói "never" để thử những điều mới trong TypeScript! Đến gặp lại lần sau, chúc các bạn ít lỗi biên dịch và suy luận kiểu mạnh mẽ!

Credits: Image by storyset