天天看點

TS學習中可能會遇到的問題

對于使用過 JavaScript 的開發者來說,對于 window.MyNamespace = window.MyNamespace || {}; 這行代碼并不會陌生。為了避免開發過程中出現沖突,我們一般會為某些功能設定獨立的命名空間。

然而,在 TS 中對于 window.MyNamespace = window.MyNamespace || {}; 這行代碼,TS 編譯器會提示以下異常資訊:

Property 'MyNamespace' does not exist on type 'Window & typeof globalThis'.(2339)

以上異常資訊是說在 Window & typeof globalThis 交叉類型上不存在 MyNamespace 屬性。那麼如何解決這個問題呢?最簡單的方式就是使用類型斷言:

(window as any).MyNamespace = {};

雖然使用 any 大法可以解決上述問題,但更好的方式是擴充 lib.dom.d.ts 檔案中的 Window 接口來解決上述問題,具體方式如下:

在 JavaScript 中,我們可以很容易地為對象動态配置設定屬性,比如:

以上代碼在 JavaScript 中可以正常運作,但在 TypeScript 中,編譯器會提示以下異常資訊:

{} 類型表示一個沒有包含成員的對象,是以該類型沒有包含 name 屬性。為了解決這個問題,我們可以聲明一個 LooseObject 類型:

該類型使用 索引簽名 的形式描述 LooseObject 類型可以接受 key 類型是字元串,值的類型是 any 類型的字段。有了 LooseObject 類型之後,我們就可以通過以下方式來解決上述問題:

對于 LooseObject 類型來說,它的限制是很寬松的。在一些應用場景中,我們除了希望能支援動态的屬性之外,也希望能夠聲明一些必選和可選的屬性。

比如對于一個表示開發者的 Developer 接口來說,我們希望它的 name 屬性是必填,而 age 屬性是可選的,此外還支援動态地設定字元串類型的屬性。針對這個需求我們可以這樣做:

其實除了使用 索引簽名 之外,我們也可以使用 TypeScript 内置的工具類型 Record 來定義 Developer 接口:

3.1 可愛又可恨的聯合類型

由于 JavaScript 是一個動态語言,我們通常會使用不同類型的參數來調用同一個函數,該函數會根據不同的參數而傳回不同的類型的調用結果:

由于 TypeScript 是 JavaScript 的超集,是以以上的代碼可以直接在 TypeScript 中使用,但當 TypeScript 編譯器開啟 noImplicitAny 的配置項時,以上代碼會提示以下錯誤資訊:

該資訊告訴我們參數 x 和參數 y 隐式具有 any 類型。為了解決這個問題,我們可以為參數設定一個類型。因為我們希望 add 函數同時支援 string 和 number 類型,是以我們可以定義一個 string | number 聯合類型,同時我們為該聯合類型取個别名:

在定義完 Combinable 聯合類型後,我們來更新一下 add 函數:

為 add 函數的參數顯式設定類型之後,之前錯誤的提示消息就消失了。那麼此時的 add 函數就完美了麼,我們來實際測試一下

在上面代碼中,我們分别使用 'semlinker' 和 ' kakuqo' 這兩個字元串作為參數調用 add 函數,并把調用結果儲存到一個名為 result 的變量上,這時候我們想當然的認為此時 result 的變量的類型為 string,是以我們就可以正常調用字元串對象上的 split 方法。但這時 TypeScript 編譯器又出現以下錯誤資訊了:

很明顯 Combinable 和 number 類型的對象上并不存在 split 屬性。問題又來了,那如何解決呢?這時我們就可以利用 TypeScript 提供的函數重載。

3.2 函數重載

函數重載或方法重載是使用相同名稱和不同參數數量或類型建立多個方法的一種能力。

在以上代碼中,我們為 add 函數提供了多個函數類型定義,進而實作函數的重載。在 TypeScript 中除了可以重載普通函數之外,我們還可以重載類中的成員方法。

方法重載是指在同一個類中方法同名,參數不同(參數類型不同、參數個數不同或參數個數相同時參數的先後順序不同),調用時根據實參的形式,選擇與它比對的方法執行操作的一種技術。是以類中成員方法滿足重載的條件是:在同一個類中,方法名相同且參數清單不同。下面我們來舉一個成員方法重載的例子:

這裡需要注意的是,當 TypeScript 編譯器處理函數重載時,它會查找重載清單,嘗試使用第一個重載定義。 如果比對的話就使用這個。 是以,在定義重載的時候,一定要把最精确的定義放在最前面。另外在 Calculator 類中,add(a: Combinable, b: Combinable){ } 并不是重載清單的一部分,是以對于 add 成員方法來說,我們隻定義了四個重載方法。

歡迎大家一起交流讨論ts學習過程中遇到的一些問題~~