深入探討 TypeScript 之基本型別
TypeScript 既然稱為 TypeScript,想當然爾型別就是該語言的重頭戲,本文我們來看看 TypeScript 對於 JavaScript 增加了哪些型別支援。
Version
TypeScript 2.3
Boolean
1 | let isDone: boolean = false; |
若值只有 true
與 false
,則其型別為 boolean
。
1 | let isDone = false; |
若變數可直接由初始值 true
或 false
獲得型別,language service 會加以提示省略型別宣告,但 isDone
本質仍是強型別 boolean
,編譯器會加以檢查,只是程式不用宣告 boolean
而已。
Number
1 | let decimal: number = 6; // 十進位 |
TypeScript 與 JavaScript 一樣,數字只有 number
型別,且本質是浮點數,不像 C# 數字有 int
、 float
與 double
。
1 | let decimal = 6; |
若變數可直接由初始值數字獲得型別,language service 會加以提示省略型別宣告,但變數本質仍是強型別 number
,編譯器會加以檢查,只是程式不用宣告 number
而已。
String
1 | let firstName: string = "Sam"; |
TypeScript 與 JavaScript 一樣,提供 string
型別,有 3 種表示法:
- 雙引號
- 單引號
- Backtick
其中 backtick 寫法,稱為 template string,可配合變數直接鑲在字串內,而不用靠 +
湊字串,可讀性較高,實務上建議使用。
1 | let firstName = "Sam"; |
若變數可直接由初始值字串獲得型別,language service 會加以提示省略型別宣告,但變數本質仍是強型別 string
,編譯器會加以檢查,只是程式不用宣告 string
而已。
雖然 TypeScript 允許 string 使用雙引號,但 language service 會提示建議使用單引號。
Array
1 | let list: number[] = [1, 2, 3]; |
TypeScript 對於陣列提供兩種寫法:
- 傳統 JavaScript 風格寫法。
- 泛型風格寫法。
兩種寫法可讀性都很高,實務上都推薦,只要團隊取得共識要使用哪種寫法即可。
Tuple
1 | let x: [string, number]; |
陣列必須每個元素的型別都相同,若你希望陣列中有不同型別的元素,則應該使用 tuple
。
實務上若你希望 function 回傳多值,且型態不相同,則可使用 tuple。
Enum
1 | enum Color {Red, Green, Blue} |
Enum 型別是強型別語言的代表,從 C 語言就已經有 enum,C++ 與 C# 也有 enum
,但 JavaScript 一直都沒有 enum
(未來有的機會也不高),TypeScript 將之補上,它有幾個優點:
- 參數之間的傳遞不用在使用 magic number,可以透過 enum 取可讀性更高的名字。
- Number 不用再直接輸入,可由 enum 型別透過 intellisense 自動帶出。
- 若輸入 enum 型別沒有的數字,編譯器會幫我們擋下來。
TypeScript 2.4 的 enum 即將支援字串,讓我們透過 enum 可以確保所輸入的是我們要的字串。
Any
1 | let notSure: any = 4; |
對於 JavaScript legacy code 或 3rd party library,若一時導入 TypeScript 有其困難,可先暫時宣告為 any
放生,讓 TypeScript 不做型別檢查,日後再慢慢重構成適當型別。
實務上不建議使用 any 型別,因為這將喪失 TypeScript 的型別檢查機制,除非有充分的理由。
Void
1 | function warnUser(): void { |
若 function 明確不傳回任何值,可宣告為 void
型別,若將此 function 的回傳值指定為變數,將編譯失敗。
Null 與 Undefined
null
與 undefined
一直是寫 JavaScript 很惱人的問題,我們必須在程式碼內判斷輸入的參數是否為 null
或 undefined
。
1 | // Compiled with --strictNullChecks |
在 TypeScript 2.0 提供了 strict null check,可以幫我們檢查參數是否為 null
或 undefined
。
若我們參數明確要接受 null
或 undefined
,則必須在參數用 |
明確宣告,否則預設不接受 null
與 undefined
。
a
可接受的型別為 number
,不接受 null
與 undefined
,但 b
可接受的型別為 number
、null
,不接受 undefined
。
若輸入的參數 a
為 null
或 undefined
,將編譯失敗。
Angular 預設並沒有啟動 strictNullChecks
,須在專案根目錄的 tsconfig.json
的 compilerOptions
加上 strictNullChecks
為 true
,TypeScript 才會啟動 strictNullChecks
。
Never
1 | function error(message: string): never { |
有些 function 永遠不傳回值,只會拋出 exception 或無窮回圈,雖然可以回傳 void
,但語意上並不精確,TypeScript 另外提出 never
型別,專門對付 exception 或無窮迴圈。
若將回傳 never
型別的 function 指定給變數,將編譯失敗。
Type Assertion
1 | let someValue: any = 'this is a string'; |
或
1 | let someValue: any = 'this is a string'; |
實務上有時宣告了 any
,但為了 intellisense 或其他變數,需要做明確的轉型,此時可使用 type assertion
明確轉型,也就是告訴編譯器:
- 我自己知道此變數的明確型別,請相信我的轉型。
雖然 type assertion 有兩種寫法,實務上建議使用第一種,第二種是為了 React 的 JSX 所妥協的語法,在 Angular 用不到。
Conclusion
- 透過 TypeScript 的明確型別宣告,可以讓編譯器幫我們檢查傳入參數是否符合型別,不用再寫一堆程式判斷。
enum
在實務上非常用有,建議大家多用。- 建議大家將
strictNullCheck
打開,讓 TypeScript 編譯器幫我們檢查惱人null
與undefined
。