Deno 入門指南
  • 前言
  • Deno 更新日誌
  • 簡介
    • Deno 跟 Node.js 的主要差異
    • Hello, World!
  • TypeScript 基礎篇
    • 變數宣告
    • 使用型別系統
    • 流程判斷與迴圈
    • 函式宣告
    • This 與 Arrow Function
    • 在函式中應用強型別
    • 介面
    • 型別別名
    • 物件導向概念
    • 類別的封裝與繼承
    • 介面與類別、抽象類別
    • 泛型的概念與實作
    • 型別補充
  • Deno CLI
    • 快速開始
    • 沙盒機制
    • URL Import
    • 編譯選項
    • 相關工具及測試
      • WebGPU API
      • Deno.resolveDns
      • 程式碼編譯器
      • 程式碼檢查器
      • 依賴檢查器
      • 文件產生器
      • 程式碼打包工具
      • 腳本安裝
      • 程式碼格式化
      • Deno 命名空間與編譯器 API
      • 使用 Deno 進行測試
  • 使用 Deno 打造多線程應用
    • 多線程概念
    • Deno Workers
    • 使用多線程計算矩陣相乘
  • 使用 Deno 打造 Web API
    • Web API 介紹
    • Oak 框架介紹
    • 使用 Denon 精簡指令
    • 實作 Web API
    • MongoDB 安裝教學
    • Deno 與 MongoDB 共舞
    • 完成第一支 Web API
    • 淺談跨來源資源共用(CORS)與解決辦法
Powered by GitBook
On this page
  • 元組
  • 列舉
  • Never
  • Unknown
  • 總結
  • 延伸閱讀

Was this helpful?

  1. TypeScript 基礎篇

型別補充

本章為本系列 TypeScript 基礎教學的最後一篇,整理了一些 TypeScript 的特殊型別:

  • 元組 (Tuple)

  • 列舉 (Enum)

  • Never

  • Unknown

元組

元組讓我們能夠對固定長度的陣列的內容作型別指定,陣列中每個元素的型別可以是不同的:

// Declare a tuple type
let x: [string, number];
// Initialize it
x = ["hello", 10]; // OK

或是我們也可以分開來賦值:

x[0] = "hello";
x[1] = 10;

相對的,若我們將 hello 和 10 的位置對調,便會發生錯誤:

// Initialize it incorrectly
x = [10, "hello"]; // Error

此外,當我們對元組中的元素賦值或訪問一個已知索引的元素時,會得到正確的型別:

// Declare a tuple type
let x: [string, number];
// Initialize it
x = ["hello", 10]; // OK
// OK
console.log(x[0].substring(1));

substring() 用於分割字串,舉例:

const str = 'Mozilla';

console.log(str.substring(1, 3));
// expected output: "oz"

console.log(str.substring(2));
// expected output: "zilla"

根據上面的程式碼可得知: 我們可以輸入 substring(起點,終點) 或是 substring(希望廢棄段落的終點)。

如果超出一開始宣告的範圍,會發生什麼情況呢?

let x: [string, number];
x = ["hello", 10];
x[2] = {};

如果新增超出一開始預定範圍的元素,需要注意新增元素的型別只能是元組中每個型別的聯合型別:

x[2] = {};// NOPE
x[2] = 12;// OK
x[2] = "Ian";// OK

列舉

列舉用於取值被限定在一定範圍內的地方,最常見的就像是一周有七天,一年有十二個月等等。

enum month {
    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}

不過需要注意的是:

定義在 enum 的成員會被賦值為從 0 開始遞增的數字,就像是:

console.log(month["JAN"] === 0); // true
console.log(month["FEB"] === 1); // true
console.log(month["JUL"] === 6); // true

相對的,列舉值與列舉名也是對映的:

console.log(0 === month["JAN"]); // true
  • 知識點: 相等 == 與全等 ===、自動轉型

    請參考本日的延伸閱讀。

根據上面的範例仔細觀察,會發現 JAN 對應到的是 0 而不是 1 ,該怎麼做呢?

enum month {
    JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}

我們可以對 enum 中的元素手動賦值,如此一來其他元素也會依循前面的元素遞增:

console.log(month["JAN"] === 1); // true
console.log(month["FEB"] === 2); // true
console.log(month["JUL"] === 7); // true

Never

Never 型別用於以下情況:

  • 沒有回傳值的函式,像是無窮迴圈。

  • 一天到晚出錯的函式

// Function returning never must not have a reachable end point
function error(message: string): never {
  throw new Error(message);
}

// Inferred return type is never
function fail() {
  return error("Something failed");
}

// Function returning never must not have a reachable end point
function infiniteLoop(): never {
  while (true) {}
}

根據第一項提到的: 沒有回傳值的函式,如果讀者有學好 JavaScript ,第一個會聯想到的應該是 void 。

不過, Never 與 Void 還是有些不同:

Void 代表的是沒有回傳值的函式,而 Never 會用於表示本就不會有回傳值,或是會拋出錯誤的函式:

function errMsg(msg: string): never {
  throw new Error(msg);
}

就上面的程式碼來看,我們可以定義了一個負責發出錯誤的函式,這時候 Never 型別就派上用場了。

此外,被宣告為 Never 型別的變數僅能被賦值給另外一個 Never :

let value :never; 
value = 123;// NOPE
value = ((msg: string)=>{ throw new Error(msg); })('Ian')// OK

Unknown

Unknown 與 Any 型別有一個共同點,就是: 所有類型都可以被歸類成 Unkown, Any 。

話雖如此, Unknown 還是有其特別之處,畢竟它的誕生就是為了解決 Any 型別不夠嚴謹的問題。

let value: unknown = 3;
value = "Ian";
value = undefined;
value = null;
value = true;

型別為 Unknown 的變數也能夠像型別 Any 的變數一樣被任意賦值。

至於與 Any 的差別到底在哪,就讓我們繼續往下看:

賦值限制

在 TypeScript 中,僅有 Any 與 Unknown 型別可以被存放任意值,作為更嚴謹的 Unknown 型別,就會有更嚴格的規範。

宣告為 Unknown 的變數僅能在被賦值為 Any 或是 Unknown 型別的變數:

let value: unknown;
let value1: unknown = value;   // OK
let value2: any = value;       // OK
let value3: number = value;   // Nope
let value4: boolean = value;    // Nope
let value5: string = value;    // Nope
// ...

筆者認為,這樣的規定是非常合理的,畢竟若 TypeScript 允許一個不確定的變數能夠被賦值給確定型別的變數,會產生很多執行上的錯誤。

看看 Any 。

限制操作

宣告為 Unknown 的變數無法進行任意操作,因為對於 TypeScript 來說,它會將該變數認定為內容不明確的變數。為了避免錯誤操作,所以不允許使用者任意操作 Unknown 型別的變數。

至於 Any 型別的變數,在被宣告的那一刻就被 TypeScript 當成放棄治療的孩子了,所以你想怎麼做都行:

let value: unknown;
let value2: any;
value.substring();
value2.substring();

錯誤訊息如下:

Object is of type 'unknown'.

總結

本章將一些之前沒有多加補充的型別一次補上,也正式將 TypeScript 基礎系列告一段落了,明天開始便會進行一系列的 Deno 入門與實戰,筆者真的是既期待又害怕趕不出文章來啊啊阿!

延伸閱讀

同樣的事情在不同人眼中可能會有不同的見解、看法。

在讀完本篇以後,筆者也強烈建議大家去看看以下文章,或許會對型別、變數宣告...等觀念有更深層的看法唷!

Previous泛型的概念與實作Next快速開始

Last updated 4 years ago

Was this helpful?

--

MDN Web Docs
官方文件
[译] TypeScript 3.0: unknown 类型
重新認識 JavaScript: Day 07 「比較」與自動轉型的規則
深入理解 TypeScript