簡介 TypeScript 所有內建的型別

TypeScript 既然稱為 TypeScript,想當然爾型別就是該語言的重頭戲,本文我們來看看 TypeScript 對於 JavaScript 增加了哪些型別支援。

Version


TypeScript 2.3

Boolean


1
2
let isDone: boolean = false;
isDone = 1; // 編譯失敗

若值只有 truefalse,則其型別為 boolean

1
let isDone = false;

若變數可直接由初始值 truefalse 獲得型別,language service 會加以提示省略型別宣告,但 isDone 本質仍是強型別 boolean編譯器會加以檢查,只是程式不用宣告 boolean 而已。

Number


1
2
3
4
let decimal: number = 6; // 十進位
let hex: number = 0xf00d; // 0x 開頭為十六進位
let binary: number = 0b1010; // 0b 開頭為二進位 (ES6)
let octal: number = 0o744; // 0o 開頭為八進位 (ES6)

TypeScript 與 JavaScript 一樣,數字只有 number 型別,且本質是浮點數,不像 C# 數字有 intfloatdouble

1
2
3
4
let decimal = 6;
let hex = 0xf00d;
let binary = 0b1010;
let octal = 0o744;

若變數可直接由初始值數字獲得型別,language service 會加以提示省略型別宣告,但變數本質仍是強型別 number編譯器會加以檢查,只是程式不用宣告 number 而已。

String


1
2
3
let firstName: string = "Sam";
let lastName: string = 'Xiao';
let sentence: string = `Hello, my name is ${firstName} ${lastName}`;

TypeScript 與 JavaScript 一樣,提供 string 型別,有 3 種表示法:

  • 雙引號
  • 單引號
  • Backtick

其中 backtick 寫法,稱為 template string,可配合變數直接鑲在字串內,而不用靠 + 湊字串,可讀性較高,實務上建議使用。

1
2
3
let firstName = "Sam";
let lastName = 'Xiao';
let sentence = `Hello, my name is ${firstName} ${lastName}`;

若變數可直接由初始值字串獲得型別,language service 會加以提示省略型別宣告,但變數本質仍是強型別 string編譯器會加以檢查,只是程式不用宣告 string 而已。

雖然 TypeScript 允許 string 使用雙引號,但 language service 會提示建議使用單引號。

Array


1
2
let list: number[] = [1, 2, 3];
let list: Array<number> = [1, 2, 3];

TypeScript 對於陣列提供兩種寫法:

  • 傳統 JavaScript 風格寫法。
  • 泛型風格寫法。

兩種寫法可讀性都很高,實務上都推薦,只要團隊取得共識要使用哪種寫法即可。

Tuple


1
2
3
let x: [string, number];
x = ["hello", 10];
x = [10, "hello"]; // 編譯失敗

陣列必須每個元素的型別都相同,若你希望陣列中有不同型別的元素,則應該使用 tuple

實務上若你希望 function 回傳多值,且型態不相同,則可使用 tuple。

Enum


1
2
enum Color {Red, Green, Blue}
let c: Color = Color.Green;

Enum 型別是強型別語言的代表,從 C 語言就已經有 enum,C++ 與 C# 也有 enum,但 JavaScript 一直都沒有 enum (未來有的機會也不高),TypeScript 將之補上,它有幾個優點:

  • 參數之間的傳遞不用在使用 magic number,可以透過 enum 取可讀性更高的名字。
  • Number 不用再直接輸入,可由 enum 型別透過 intellisense 自動帶出。
  • 若輸入 enum 型別沒有的數字,編譯器會幫我們擋下來。

TypeScript 2.4 的 enum 即將支援字串,讓我們透過 enum 可以確保所輸入的是我們要的字串。

Any


1
2
3
let notSure: any = 4;
notSure = "maybe a string instead"; // 編譯器不會檢查
notSure = false; // 編譯器不會檢查

對於 JavaScript legacy code 或 3rd party library,若一時導入 TypeScript 有其困難,可先暫時宣告為 any 放生,讓 TypeScript 不做型別檢查,日後再慢慢重構成適當型別。

實務上不建議使用 any 型別,因為這將喪失 TypeScript 的型別檢查機制,除非有充分的理由。

Void


1
2
3
4
5
function warnUser(): void {
alert("This is my warning message");
}

let message = warnUser(); // 編譯失敗

若 function 明確不傳回任何值,可宣告為 void 型別,若將此 function 的回傳值指定為變數,將編譯失敗。

Null 與 Undefined

nullundefined 一直是寫 JavaScript 很惱人的問題,我們必須在程式碼內判斷輸入的參數是否為 nullundefined

1
2
3
4
// Compiled with --strictNullChecks
function sum(a: number , b: number | null ) {
return a + b; // Produces value of type number
}

在 TypeScript 2.0 提供了 strict null check,可以幫我們檢查參數是否為 nullundefined

若我們參數明確要接受 nullundefined,則必須在參數用 | 明確宣告,否則預設不接受 nullundefined

a 可接受的型別為 number ,不接受 nullundefined ,但 b 可接受的型別為 numbernull ,不接受 undefined

若輸入的參數 anullundefined,將編譯失敗。

type000

Angular 預設並沒有啟動 strictNullChecks,須在專案根目錄的 tsconfig.jsoncompilerOptions 加上 strictNullCheckstrue,TypeScript 才會啟動 strictNullChecks

Never


1
2
3
4
5
6
7
8
9
10
11
function error(message: string): never {
throw new Error(message);
}

function infiniteLoop(): never {
while (true) {
}
}

let a = error('Sam'); // 編譯失敗
let b = infiniteLoop('Sam'); // 編譯失敗

有些 function 永遠不傳回值,只會拋出 exception 或無窮回圈,雖然可以回傳 void但語意上並不精確,TypeScript 另外提出 never 型別,專門對付 exception 或無窮迴圈。

若將回傳 never 型別的 function 指定給變數,將編譯失敗。

Type Assertion


1
2
let someValue: any = 'this is a string';
let strLength: number = (<string>someValue).length;

1
2
let someValue: any = 'this is a string';
let strLength: number = (someValue as string).length;

實務上有時宣告了 any,但為了 intellisense 或其他變數,需要做明確的轉型,此時可使用 type assertion 明確轉型,也就是告訴編譯器:

  • 我自己知道此變數的明確型別,請相信我的轉型。

雖然 type assertion 有兩種寫法,實務上建議使用第一種,第二種是為了 React 的 JSX 所妥協的語法,在 Angular 用不到。

Conclusion


  • 透過 TypeScript 的明確型別宣告,可以讓編譯器幫我們檢查傳入參數是否符合型別,不用再寫一堆程式判斷。
  • enum 在實務上非常用有,建議大家多用。
  • 建議大家將 strictNullCheck 打開,讓 TypeScript 編譯器幫我們檢查惱人 nullundefined

Reference


TypeScript, Handbook : Basic Types

2017-06-15