溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

TypeScript應該盡量避免的語法有哪些

發布時間:2022-04-19 15:15:46 來源:億速云 閱讀:150 作者:iii 欄目:開發技術

今天小編給大家分享一下TypeScript應該盡量避免的語法有哪些的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

避免枚舉

枚舉提供了一組常量。在下面的例子里,HttpMethod.Get 是字符串 ‘Get’ 的名字。HttpMethod 類型和一個聯合類型是一樣的,如 'GET' | 'POST'。

enum HttpMethod {
  Get = 'GET',
  Post = 'POST',
}
const method: HttpMethod = HttpMethod.Post;
method; // Evaluates to 'POST'

下面是支持使用枚舉的原因:

假設,我們最終要替換 ‘POST’ 為 ‘post’。我們只要替換枚舉的值就能達成這一目的。我們其他的代碼因為引用的是 HttpMethod.Post ,所以完全不用改。

現在假設,如果我們用聯合類型來實現這個場景。我們定義了聯合類型 'GET' | 'POST',然后我們決定把它們改為小寫的 'get' | 'post'?,F在如果使用 'GET' 或者 'POST' 作為 HttpMethod 的代碼就會報類型錯誤。我們需要把所有的代碼手動改一遍。從這個例子來說,使用枚舉能簡單一些。

這個支持使用枚舉的例子可能不是那么有說服力。當我們增加了一個枚舉和聯合類型的時候,實際上在創建以后是很少更改的。使用聯合類型,確實會帶來更多的更改成本,但是其實不是一個問題,因為實際上是很少更改的。即便要更改,因為有類型錯誤,我們并不害怕少改了。

使用枚舉的壞處是:

我們需要適應 TypeScript 的語法。TypeScript 應該是 JavaScript,但是增加了靜態類型。如果我們去掉 TypeScript 的類型,我們就應該得到一份完整有效的 JavaScript 的代碼。(譯者注:這個原因是整篇文章的核心,核心好處之一就是,你可以通過 esbuild 而不是 tsc 完成你的 ts 代碼到 js 代碼的轉換,這個速度差距可能是 10-1000倍。。并且不引入 tsc,代表著少了一個可能出問題的地方。)在 TypeScript 的官方文檔中,之前描述 TypeScript 的文檔是 “類型級別的擴展”:即 TypeScript 是 JavaScript 類型級別的擴展,所有 TypeScript 的特性不改變運行時的行為。

下面是一個類型級別擴展的例子, TypeScript 的例子:

function add(x: number, y: number): number {
  return x + y;
}
add(1, 2); // Evaluates to 3

TypeScript 的編譯器檢查了代碼的類型。然后生成了 JavaScript 的代碼。很幸運,這個過程很簡單:編譯器只要把類型標注去掉就好了。在這個例子里,只要把 :number 去掉,下面就是完美的 JavaScript 代碼:

function add(x, y) {
  return x + y;
}
add(1, 2); // Evaluates to 3

絕大部分 TypeScript 的特性都有這個特性,遵循了類型級別擴展的法則。要得到 JavaScript 代碼,只需要去掉類型標準即可以。

然而,枚舉打破了這個法則。HttpMethod 和 HttpMethod.Post是一部分的類型。他們應該被去除。然而,如果編譯器去除這些代碼,就會有問題,因為我們實際上在把 HttpMethod.Post 當成值類型在使用。如果編譯器簡單刪除這些代碼,這些代碼就不能跑了。

/* This is compiled JavaScript code referencing a TypeScript enum. But if the
 * TypeScript compiler simply removes the enum, then there's nothing to
 * reference!
 *
 * This code fails at runtime:
 *   Uncaught ReferenceError: HttpMethod is not defined */
const method = HttpMethod.Post;

TypeScript 的解決方案,就是打破自己的規則。當編譯一個枚舉的時候,編譯器會自己生成一些 JavaScript 代碼。其實很少 TypeScript 特性會這樣做,這個其實讓 TypeScript 的編譯模型變得復雜了。因為這些原因,我們建議避免使用枚舉,而用聯合類型來取代它。

為什么類型級別擴展這個規則這么重要呢?

讓我們來看,這個法則在和 JavaScript 和 TypeScript 的工具鏈生態互動時,會發生什么。TypeScript 的項目都是從 JavaScript 項目繼承而來的,所以使用打包工具和編譯工具,例如 webpack 和 babel 是很正常的。這些工具都是為了 JavaScript 設計的,即便在今天,依然是關注在 JavaScript 上。每一個工具都有自己的生態。這里有無數的 Babel 和 Webpack 自有的生態的插件。

有可能讓所有 Babel 和 Webpack 以及他們的生態插件支持 TypeScript 么?對于大部分 TypeScript 語言來說,實際上類型擴展規則讓這些內容支持 TypeScript 很簡單。工具只要去掉類型標準,然后對其余的 JavaScript 做剩下的工具就好了。

當對于像枚舉這樣的特性(包括名字空間 namespaces),這個事兒要復雜一些。不能簡單移除枚舉。工具需要把 enum HttpMethod { ... } 轉譯 成合適的 JavaScript 代碼,因為 JavaScript 并沒有 enum 關鍵字。

這會帶來一些實際的工作量,來處理 TypeScript 自己打破自己的類型擴展法則的問題。像 Babel、webpack 以及他們的生態插件,都是先對 JavaScript 作為設計對象,TypeScript 一般來說只是他們支持的一個功能。很多時候,TypeScript 的支持并不能收到像 JavaScript 一樣的支持,就會有很多 Bug。(譯者注:考慮 JavaScript 實際上讓這些工具和插件的難度小很多,考慮 TypeScript,很多問題其實變復雜了,而且這個復雜度的提升不一定是有價值的。時至今日,依然是 JavaScript 的代碼和需求遠遠大于 TypeScript。即便出于降低這些工具的復雜度的目的,也不應該為了解決 TypeScript 的問題而引入 這些問題。最核心的運行時,依然,以及必然是 JavaScript。)

很多工具的工作主要是在處理變量聲明和函數聲明,這些事情其實相對都是比較容易做的。但是牽扯枚舉和名字空間,就不能僅僅去掉類型標注開始做邏輯了。你當然可以信賴 TypeScript 的編譯器,但是很多不常用的工具可不一定考慮這個問題了。

當你的編譯器、打包器、壓縮器、linter、代碼格式器(譯者注:其實代碼格式器很容易造成 bug,尤其對于 TypeScript)只要發生了一個對于上述的事兒處理有問題,是非常難進行 debug 的。編譯器的 Bug 是非常非常難找的(譯者注:當出現一個 bug,你會第幾直覺認為是編譯器的錯誤呢?其實不使用這些特性,你的代碼是不依賴 TypeScript 編譯器的,這一點至關重要。)。主要這篇文章的這些文字:經歷了幾周以后,在我的同事的幫助下,我們對于這個bug牽扯的范疇有了更深的認識。(注意加粗字體)(譯者注:我本來花了大約兩個月的時間去研究 TypeScript 的裝飾器以及裝飾器元數據,然后計劃把他們加入到我自己的框架里。但是最后沮喪的發現,如果我引入他們,我就沒有辦法用 esbuild 了,原因是 esbuild 不計劃支持 TypeScript 的裝飾器元數據,但是支持了裝飾器,但是這個支持其實也很新,而我的整個框架其實是以 esbuild 為基石的。我很沮喪,放棄了 TypeScript 的裝飾器)(譯者注:引入 tsc 是不明智的,因為 tsc 非常非常復雜。實際上,你只用類型的話,在代碼編寫階段基本也就完成了絕大部分 tsc 的事情。在最后用 esbuild 一去類型,就可以繼續了。)

避免名字空間

名字空間類似 module,但是一個文件里可以有多個名字空間。例如,我們在一個文件里引入了不同名字空間的導出代碼,以及它們對應的測試。(我們不建議這樣使用名字空間,這里只是作為一個探討的例子。)

namespace Util {
  export function wordCount(s: string) {
    return s.split(/\b\w+\b/g).length - 1;
  }
}

namespace Tests {
  export function testWordCount() {
    if (Util.wordCount('hello there') !== 2) {
      throw new Error("Expected word count for 'hello there' to be 2");
    }
  }
}

Tests.testWordCount();

名字空間在實踐上會造成一些問題。在上面的枚舉的例子里,我們看到了 TypeScript 的類型擴展法則。通常,TypeScript 去除類型標注,留下的就是 JavaScript 的代碼。

名字空間自然也打破了這一設定。在 namespace Util { export function wordCount ... } 代碼里,我們不能僅僅靠去除類型標注就獲得 JavaScript 的代碼。整個名字空間就是一個 TypeScript 的類型定義!在其他的代碼里使用 Util.wordCount(...) 會發生什么呢?如果我們刪除 Util 名字空間,然后生成 JavaScript 代碼,Util 就沒有了。所以 Util.wordCount(...) 也不能工作。

就和枚舉一樣,TypeScript 也不能僅僅刪除名字空間定義,而要生成一些 JavaScript 的代碼。

對于枚舉,我們建議用聯合類型來取代。對于名字空間,我們建議就用 ESM 取代就好了。雖然創建很多文件很麻煩。但是兩者能達成的效果是完全一樣的。

避免裝飾器(對于現在而言)

裝飾器是一個可以修改和取代其他函數或者類的方法。這里是一個從 TypeScript 官方文檔里找到的裝飾器的例子:

// This is the decorator.
@sealed
class BugReport {
  type = "report";
  title: string;

  constructor(t: string) {
    this.title = t;
  }
}

@sealed 裝飾器暗示了C# 的 sealed 裝飾器。這個裝飾器可以防止其他類繼承這個類。我們可以實現一個 sealed 的函數,然后接受一個類,修改它,讓它不能繼承這個類。

裝飾器一開始是首先在 TypeScript 添加的,然后 JavaScript(ECMAScript)才開始了標準化進程。在 2022 年1月,裝飾器依然是一個 ECMAScript 提案階段 2 的提案。階段 2 代表在 “draft”(起草)階段。裝飾器提案似乎一直停滯在委員會中:實際上,這個提案是在 2019 年 2 月到達階段 2 的。

我們建議在 stage 3 前,避免使用裝飾器。stage 3 指 “candidate” 階段,或者 stage 4 “finished” 階段。

有這樣的可能,即 ECMAScript 永遠不完成裝飾器提案。如果這個提案不完成,裝飾器的處境就和枚舉、名字空間一樣。使用裝飾器,就代表著,打破了 TypeScript 的類型擴展規則,并且使用這個特性,很多打包工具,可能都是有問題的。我們不知道多會能讓裝飾器通過,但是裝飾器帶來的好處并沒有那么大,所以我們選擇等待。

一些開源的庫,例如有名的 TypeORM,非常重的使用了裝飾器。我們承認,如果遵守我們的建議,就不能使用 TypeORM。當然使用 TypeORM 和裝飾器有時候是好的選擇,但是你應該明白這么做帶來的問題,你要知道,目前裝飾器的提案的標準化過程可能永遠不會結束。(譯者注:如果你想享受 esbuild 帶來的好處,裝飾器用的深就可能是個問題。當然,如果你的業務可以自閉在一套裝飾器寫的框架里,可能也不是非常大的問題。但是,如果 JS 的裝飾器出現,現有的裝飾器框架可能就有問題了。)

避免 Private 關鍵字

TypeScript 有兩種方式讓一個類型屬性私有。老的方法是 private 關鍵字,這個是 TypeScript 獨有的。目前還有一個新的方式:#somePrivateField,這個是 JavaScript 的方式。下面是一個例子:

class MyClass {
  private field1: string;
  #field2: string;
  ...
}

我們建議 #somePrivateField 字段。但是這兩個方法基本是等同的。但是我們建議更多使用 JavaScript 的特性。

以上就是“TypeScript應該盡量避免的語法有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女