TypeScript - Never: 了解底層類型

Hello, 有志青年程式設計師!今天,我們將深入TypeScript中一個較為神秘的類型:never類型。如果你是程式設計的新手,別擔心——我會逐步引導你理解這個概念,就像我這些年來對無數學生所做的那樣。所以,拿起你喜歡的飲料,讓我們一起踏上這場令人興奮的TypeScript之旅吧!

TypeScript - Never

What is the never type?(什么是never类型?)

TypeScript中的never類型通常被稱為"底層類型"或"空類型"。它代表一個永不會發生的類型。現在,你可能會想:"我們為什麼需要一個從不發生的類型呢?" 嗯,我好奇的朋友們,這比你想像的還要有用!

When is never used?(何时使用never?)

  1. 總是代表不可能的情況
  2. 處理徹底的檢查
  3. 在永不返回的函數中

讓我們看一些例子來使這些概念更清晰。

Example 1: Representing Impossible Scenarios(例子1:表示不可能的情况)

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

let result = throwError("Oops! Something went wrong!");
console.log(result); // 這行代碼永遠不會被達到

在這個例子中,throwError函數保證會抛出一個錯誤並永遠正常返回。因此,它的返回類型是never

把它想像成這樣:如果你在烤蛋糕,配方說"烤到永遠",你就知道那個蛋糕不會從烤箱裡出來!

Example 2: Exhaustive Checks(例子2:彻底的检查)

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;
}
}

在這裡,never幫助我們確保我們已經覆蓋了所有可能的形狀。如果我們在Shape類型中添加了一個新形狀但忘記在getArea中為它添加一個案例,TypeScript會給我們一個錯誤。這就像有一個有用的助手在提醒你忘記了什麼!

Example 3: Functions That Never Return(例子3:永不返回的函数)

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

這個函數將永遠運行(或者直到你的電腦耗盡記憶體)。因为它從不結束執行,所以它的返回類型是never。這就像告訴你的朋友你會"永遠"停止說話——他們知道他們會有一段長時間的對話!

The never type vs. void(never类型与void类型的区别)

現在,你可能會想:"nevervoid有什麼區別?" 好問題!讓我們來分析一下。

void(void类型)

void類型用於當函數不返回任何值,但它會完成其執行。

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

logMessage("Hello, TypeScript!"); // 這個函數返回undefined

never(never类型)

另一方面,never類型用於當函數從不完成其執行或總是抛出錯誤。

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

failwithError("This function never returns!");

這樣想:void就像去一家商店並空手而歸,而never就像踏上沒有目的地的旅程——你從不回來!

Practical Uses of never(never的实用用途)

讓我們看看一些never可以派上用場的更實際的例子。

Example 4: Type Guards(例子4:类型守卫)

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); // 如果shape既不是Square也不是Circle,則出錯
}
}

在這個例子中,assertNever幫助我們捕捉到可能錯過的任何情況。這就像在學習擲骰子時有一個安全網!

Example 5: Unreachable Code Detection(例子5:不可达代码检测)

function neverReaches(): never {
while (true) {
// 一些操作
}
console.log("This line will never be reached");  // TypeScript错误
}

TypeScript足夠聰明,知道console.log語句永遠不會達到,並會給你一個錯誤。這就像有一個GPS告訴你當你試圖開車到一個不存在的地方時!

Methods and Properties of never(never的方法和属性)

現在,你可能會想,"never"有沒有自己的方法和屬性。事實是,"never"沒有自己的方法和屬性,因为它代表一個永不會發生的類型。然而,它仍然是TypeScript類型系統中重要的一部分。

這裡有一個總結你可以(或不可以)與"never"進行的操作的表格:

操作 結果 解釋
賦值給 "never" ✅ 允許 任何類型都可以賦值給 "never"
將 "never" 賦值給其他類型 ❌ 不允許 "never" 不能賦值給任何其他類型
在 "never" 上調用方法 ❌ 不允許 因為 "never" 應該從不發生,所以你不能在它上面調用方法
在聯合中使用 "never" ✅ 允許但沒有影響 在聯合類型中 "never" 被忽略
在交集中使用 "never" ✅ 允許並且結果為 "never" 任何類型與 "never" 的交集結果都是 "never"

Conclusion(结论)

親愛的學生們,這就是我們對"never"類型的探索,我們一起走過了它的角落和細節。記住,"never"就像那個總是取消計劃的朋友——他從不露面,但仍然重要的是要把它放在心上!

理解"never"可能起初看起來有些複雜,但隨著練習,你會發現它是你TypeScript工具箱中無價的工具。它幫助你的代碼變得更健壯,捕捉潛在的錯誤,甚至讓你更深入地思考你的函數行為。

繼續編程,持續學習,並且在TypeScript中不要拒絕嘗試新事物!直到下一次見面,願你的編譯錯誤少之又少,類型推斷強大無比!

Credits: Image by storyset