TypeScrip 基礎與進階概念_Part 1
型別推論 ( Type Inference )
型別推論 就是在没有明確指定型別的情況下,由 TS 自動判斷型別
型別斷言 ( Type Assertion )
型別斷言 則是手動指定資料型別,可以覆蓋掉 TS 自動推論的資料型別
語法
型別斷言有兩種寫法:
- <型別>值 ( angle-bracket <> )寫法
1 | let code: any = 123; |
- 值 as 型別 ( as keyword )寫法
1 | let code: any = 123; |
- 非空斷言運算符(Non-null Assertion Operator)
1 | function getElementText(id: string): string { |
當你確定一個變數或屬性在某一時刻不會是 null 或 undefined 時,可以使用 ! 來告訴 TypeScript 編譯器你有這個保證,從而避免類型檢查錯誤。
使用情境
- 情境1. JS 程式碼轉換成 TS 程式碼我們將上方的 JS 程式碼放進 TS 中會出現錯誤,因為 foo 的型別推論是沒有任何屬性的物件,因此,不能在屬性上添加 bar 或 bas ,這時候透過型別斷言可以避免這個問題
1
2
3
4// Javajcript
const foo = {}
foo.bar = 123 // Error: property 'bar' does not exist on `{}`
foo.bas = 'hello' // Error: property 'bas' does not exist on `{}`
1 | // TypeScript |
- 情境2. 將聯合型別的變數指定為更加具體的型別
聯合型別,表示值可以是多種指派型別的其中一種。
下方的程式碼表示 getLength 這個函式的參數可能為字串或數字的其中一種,然而 length 不是字串和數字的的共同属性,會報錯。
1 | function getLength(something: string | number): number { |
這時候就可以使用「型別斷言」將 something 斷言為字串(string)
1 | function getLength(something: string | number): number { |
TS 的型別斷言並非型別轉換(Type casting)
型別斷言有點類似其他強語言如 Java 中的型別轉換,但實際上仍是不同的。斷言聯合型別中不存在的型別是不行的。
1 | function toBoolean(something: string | number): boolean { |
型別註解 (Type Annotation)
型別註解則是明確指定資料型別
語法
變數、參數或屬性:型別
1 | //變數的型別註解 |
補充:型別註解 v.s 型別斷言的比較
- 大部分情況下會使用型別註解 ; 型別斷言使用情境較少。
- 型別註解告訴編譯器這個資料必須永遠都是這個型別 ; 而型別斷言則主要用在覆蓋 TS 編譯器自動進行的型別推斷和型別相容性規則(Type Compatibility),告訴編譯器你知道這個值要符合斷言的型別,從而避免了上面範例中型別不兼容的錯誤產生。關於兼容性的討論 =>stackoverflow
- 型別註解大部分使用在初始化階段,像是宣告變數、函式參數或回傳值型別等 ; 而型別斷言可能用在接收外部參數,中間過程需要明確指定資料型別的時候。
基本型別 (Basic Types)
- 原始型別( Primitive Types):
- number (數字)
- string (字串)
- boolean (布林值)
- undefined
- null
- symbol
- BigInt
BigInt (TypeScript 3.2 之後支援)
物件型別 Object Types:
- Function (函式)
- Array (陣列)
- Object (物件)
- Class (類別)
- Class (類別) new 出的物件實例 (instance)
void (空值):
- 表示不回傳任何值(等於預設回傳 undefined)
- 只能將它賦值為 undefined 和 null
Null 和 Undefined
與 void 的區別是,undefined 和 null 是所有型別的子型別。
也就是說 undefined 型別的變數,可以賦值給 number 型別的變數:
1 | // 這樣不會報錯 |
而 void 型別的變數不能賦值給 number 型別的變數:
1 | let u: void; |
Any (任意值)
宣告一個變數為任意值之後,對它的任何操作,返回的內容的型別都是任意值。
在任意值上訪問任何屬性都是允許的:
1 | let anyThing: any = 'hello'; |
也允許呼叫任何方法:
1 | let anyThing: any = 'Tom'; |
未宣告型別的變數
變數如果在宣告的時候,未指定其型別,那麼它會被識別為任意值型別:
1 | let something: any; |
聯合型別(Union Types)
聯合型別使用 |
分隔每個型別,表示取值可以為多種型別中的一種。
當 TypeScript 不確定一個聯合型別的變數到底是哪個型別的時候,我們 只能存取此聯合型別的所有型別裡共有的屬性或方法:
1 | function getLength(something: string | number): number { |
上例中,length 不是 string 和 number 的共有屬性,所以會報錯。
存取 string 和 number 的共同屬性是沒問題的:
1 | function getString(something: string | number): string { |
介面(Interfaces)
在 TypeScript 中,我們使用介面(Interfaces)來定義物件的型別。
TypeScript 中的介面是一個非常靈活的概念 :
- 用於對 類別的一部分行為 進行抽象
- 用於對 物件的形狀(Shape) 進行描述
在物件導向程式語言中,介面(Interfaces)是一個很重要的概念,它是對行為的一種抽象,而具體如何行動則需要由類別(classes)去實現(implement)。
賦值的時候,變數的形狀必須和介面的形狀保持一致
1 | // 正確示範 |