【TypeScript 演化史 -- 4】更多的字面量類型 與 內置類型聲明

做者:Marius Schulz
譯者:前端小智
來源:Marius Schulz

阿里雲雙12已開啓,新老用戶都可參與,2核1G雲服務器僅需79元,,更多服務器配置及價格請關注:Hi拼團,或點此瞭解「雲上爆款1折特惠活動」。同時,建議在購買阿里雲相關產品前先領取阿里雲2000元代金券會更優惠哦。前端


爲了保證的可讀性,本文采用意譯而非直譯。git

TypeScript 1.8 引入了字符串字面量類型,用於將變量限制爲可能的字符串值的有限集。在 TypeScript 2.0 中,字面量類型再也不侷限於字符串。如下字面量類型已添加到類型系統中:es6

  • boolean 字面量類型
  • 數字字面量類型
  • 枚舉字面量類型

接下來,來看看這個類型對應的一些事例。github

boolean 字面量類型

下面的示例定義了兩個常量 TRUEFALSE,它們分別持有 true false 值:web

const TRUE: true = true; // OK
const FALSE: false = false; // OK

試圖爲每一個局部變量分配相反的布爾值會致使類型錯誤:typescript

const TRUE: true = false;
// Error: Type 'false' is not assignable to type 'true'

const FALSE: false = true;
// Error: Type 'true' is not assignable to type 'false'

隨着 boolean 字面類型的引入,預約義的 boolean 類型如今等價於 true | false 的聯合類型:npm

let value: true | false; // Type boolean

雖然 boolean 字面量類型在隔離時不多有用,但它們與標記聯合類型和基於控制流的類型分析結合使用時很是有效。例如,能夠定義一個泛型 Result <T>類型,該類型要麼包含一個類型爲 T 的值,要麼包含一個類型爲 string 的錯誤消息,以下所示json

type Result<T> =
  | { success: true; value: T }
  | { success: false; error: string };

這是一個接受參數的函數:segmentfault

function parseEmailAddress(
  input: string | null | undefined
): Result<string> {
  // 若是 input 爲 null,undefined 或空字符串   
  //(全部都是虛假的值),就直接返回。
  if (!input) {
    return {
      success: false,
      error: "The email address cannot be empty."
    };
  }

  // 咱們只檢查 input 是否與模式匹配   
  // <something> @ <something> . <something>   
  // 保持簡單,正確驗證電子郵件地址 
  if (!/^\S+@\S+\.\S+$/.test(input)) {
    return {
      success: false,
      error: "The email address has an invalid format."
    };
  }

  return {
    success: true,
    value: input
  };
}

請注意,啓用 strictNullChecks 選項後,string 是不可爲 null 的類型。爲了使函數的 input 參數接受可爲 null 的類型的值,必須在聯合類型中明確包含 nullundefined 類型。promise

咱們如今能夠像下面這樣調用 parseEmailFunction

const parsed = parseEmailAddress("example@example.com");

if (parsed.success) {
  parsed.value; // OK
  parsed.error; // Error
} else {
  parsed.value; // Error
  parsed.error; // OK
}

請注意,某些屬性訪問表達式用紅色波浪線下劃線:

clipboard.png

這樣作的好處是,編譯器僅在檢查了 parsed.success 後才容許我們使用valueerror屬性:

  • 若是 parsed.successtrue,則 parsed 的類型必須爲 { success: true; value: string }。在這種狀況下,我們能夠訪問 value,但不能訪問 error
  • 若是 parsed.successfalse,則 parsed 的類型必須爲 { success: false; error: string }。在這種狀況下,我們能夠訪問 error,但不能訪問 value

數字字面量類型

與字符串字面量類型相似,咱們能夠將數值變量限制爲已知值的有限集

let zeroOrOne: 0 | 1;

zeroOrOne = 0;
// OK

zeroOrOne = 1;
// OK

zeroOrOne = 2;
// 錯誤:類型 '2' 不能分配給類型 '0 | 1'

在實踐中,咱們能夠在處理端口號時使用數字字面量。不安全的 HTTP 使用端口 80,而 HTTPS 使用端口 443。我們能夠編寫一個 getPort 函數,並在其函數簽名中編碼僅有的兩個可能的返回值

function getPort(scheme: "http" | "https"): 80 | 443 {
  switch (scheme) {
    case: "http":
      return 80;
    case: "https":
      return 443;
  }
}

const httpPort = getPort('http'); // Type 80 | 443

若是咱們將字面量類型與 TypeScript 的函數重載結合起來,那就更有趣了。這樣,咱們能夠爲 getPort函數的不一樣重載提供更具體的類型。

function getPort(scheme: "http"): 80;
function getPort(scheme: "https"): 443;
function getPort(scheme: "http" | "https"): 80 | 443 {
  switch (scheme) {
    case "http":
      return 80;
    case "https":
      return 443;
  }
}

const httpPort = getPort("http"); // Type 80
const httpsPort = getPort("https"); // Type 443

如今,當返回的時候與比較的值永遠都不會相同的狀況下,編輯器會提示咱們,例如,將 httpPort 與值 443 進行比較時:

clipboard.png

因爲 httpPort 的類型爲 80,所以它始終包含值 80,該值固然永遠不會等於值 443。在這種狀況下,TypeScript 編譯器能夠幫助我們檢測錯誤的邏輯和無效的代碼。

枚舉字面量類型

最後,我們還可使用枚舉做爲字面量類型。繼續前面的示例,實現一個給定端口(80443)映射到相應方案(分別爲 HTTPHTTPS)的函數。爲此,咱們首先聲明一個const enum,它對兩個端口號進行構建:

const enum HttpPort {
  Http = 80,
  Https = 443
}

如今是 getScheme 函數,再次使用函數重載來實現專門的類型註解:

function getScheme(port: HttpPort.Http): "http";
function getScheme(port: HttpPort.Https): "https";
function getScheme(port: HttpPort): "http" | "https" {
  switch (port) {
    case HttpPort.Http:
      return "http";
    case HttpPort.Https:
      return "https";
  }
}

const scheme = getScheme(HttpPort.Http);
// Type "http"

常量枚舉沒有運行時表現形式(除非提供了preserveConstEnums編譯器選項),也就是說,enum 用例的常量值將被內聯到使用它們的任何地方。下面是通過編譯的 JS 代碼,去掉了註解:

function getScheme(port) {
  switch (port) {
    case 80:
      return "http";
    case 443:
      return "https";
  }
}
var scheme = getScheme(80);

是否是超級簡潔?

TypeScript 2.0 讓我們以更細粒度地控制項目中包含哪些內置 API 聲明。之前,只有在的項目配置 ES6 相關的包才能訪問 ES6 Api。如今,內置的標準庫聲明已經模塊化,TypeScript 容許咱們選擇包含哪一種類型聲明。

--lib 編譯器選項

JS 標準庫的類型聲明被劃分爲一組 API 組。 2016 年 11 月下旬撰寫本文時,定義瞭如下組

  • dom
  • webworker
  • es5
  • es6 / es2015
  • es2015.core
  • es2015.collection
  • es2015.iterable
  • es2015.promise
  • es2015.proxy
  • es2015.reflect
  • es2015.generator
  • es2015.symbol
  • es2015.symbol.wellknown
  • es2016
  • es2016.array.include
  • es2017
  • es2017.object
  • es2017.sharedmemory
  • scripthos

能夠經過 --lib 命令行選項或 tsconfig.json 中的 lib 屬性將上述組的任何子集傳遞給TypeScript 編譯器。TypeScript 將只注入你指定的類型;也就是說,它會將全部其餘 API 組視爲不存在於你的的環境中。

若是未明確提供 lib 選項,則 TypeScript 將隱式注入Web開發所需的API組。

注意:若是--lib沒有指定默認庫。默認庫是

  • For --target ES5:["dom", "es5", "scripthost"]
  • For --target ES6: ["dom", "es6", "dom.iterable", "scripthost"]

以 es5 爲 target 的 TypeScript 項目中使用 ES6 Promise

假設你正在處理一個 targetes5 項目,爲了讓它能在全部主流瀏覽器中運行。你的tsconfig.json 多是這樣的:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}

由於 lib 選項沒有指定,因此默認狀況下 TypeScript 會注入 API 組 "dom""es5""scripthost"。如今但願在項目中使用ES6 中原生的 Pormise。這些在 ES5 中並無,因此我們須要安裝一個 polyfill 來讓咱們的代碼在舊的瀏覽器中運行:

npm install --save es6-promise

而後能夠在入口文件中導入對應的庫

import "es6-promise";

有了這個 polyfill,如今就能夠在應用程序中使用 Promise,代碼也能夠正常運行。然而,TypeScript 會給你一個編譯時錯誤: Cannot find the name 'Promise'。這是由於 Promise 的類型聲明不包含在任何注入的 API 組中。

clipboard.png

咱要讓 TypeScript 知道 Promise 會在運行時存在,這就是 lib 編譯器選項發揮做用的地方:

clipboard.png

注意,一旦覆蓋了默認值,就必須顯式地提供全部API組,以下所示:

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es5",
    "noImplicitAny": true,
    "strictNullChecks": true,
    "lib": ["dom", "es5", "es2015.promise"]
  }
}

如今編輯器就不會在報錯了:

clipboard.png


編輯中可能存在的bug無法實時知道,過後爲了解決這些bug,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug

原文:

https://mariusschulz.com/blog...
https://mariusschulz.com/blog...


交流

乾貨系列文章彙總以下,以爲不錯點個Star,歡迎 加羣 互相學習。

https://github.com/qq449245884/xiaozhi

由於篇幅的限制,今天的分享只到這裏。若是你們想了解更多的內容的話,能夠去掃一掃每篇文章最下面的二維碼,而後關注我們的微信公衆號,瞭解更多的資訊和有價值的內容。

clipboard.png

相關文章
相關標籤/搜索