一. JavaScript 型別
JavaScript 有 7 種型別:Boolean、Number、String、Undefined、Null、Object,以及 ES6 新增的 Symbol
這 7 種 TypeScript 全都支援:
// JavaScript支持的7种类型
let isDone: boolean = false; // 布尔值
let decimal: number = 6; // 数值
let color: string = 'blue'; // 字符串
let u: undefined = undefined; // Undefined
let n: null = null; // Null
let obj: object = {}; // Object
let sym: symbol = Symbol(); // Symbol
變數宣告
上面範例中的變數都是透過 let 宣告的,其實有 3 種變數宣告方式:
-
var:函式作用域 -
let:區塊級作用域 -
const:區塊級作用域,常數(不允許修改)
例如:
var a: string = 'a';
let b: string = 'b';
const c: string = 'c';
與 JavaScript 變數宣告方式完全一致,不再贅述,具體見 Variable Declarations
P.S. 實際上, let 和 const 最終都會被編譯成 var ,區塊級作用域等特性透過變數重新命名來模擬
二. TypeScript 型別
TypeScript 共有 13 種基本型別,除了 JavaScript 所有的 7 種之外,還有:
-
Array:陣列,表示一組型別相同的元素
-
Tuple:元組,表示一組固定數量的元素(不要求型別相同),如二元組、三元組
-
Enum:列舉,常數集合
-
Any:任意型別,表示未知型別,比如動態內容(使用者輸入、或第三方類別庫)或不知道型別的東西(混合型別陣列),可以宣告
any型別繞過型別檢查 -
Void:空型別,表示沒有型別,比如無回傳值函式的回傳值型別
-
Never:絕不存在的值的型別,如永遠不會回傳的函式(必定拋異常的,或函式體有死迴圈的)的回傳值型別
範例如下:
// TypeScript新增的6种类型
let list: number[] = [1, 2, 3]; // 数组
let list: Array<number> = [1, 2, 3]; // 数组
let x: [string, number] = ["hello", 10]; // 元组
enum Color {Red = 'r', Green = 'g', Blue = 'b'} // 枚举
let notSure: any = 4; // 任意类型
let list: any[] = [1, true, "free"]; // 任意类型数组(未知类型)
function warnUser(): void {/*..*/} // 空类型
function neverReturn(): never {throw 'error';} // 绝不存在的类型
需要注意幾點:
-
Array 型別有 2 種宣告格式(
elemType []和Array<elemType>) -
存取 Tuple 發生越界時,套用聯合型別(union type),所以上例中
x[10]的型別是string | number -
Enum 值可以省略,預設按 key 宣告順序從
0開始。如果指定了數值,後一項的值在此基礎上遞增,否則要求之後的項都要指定值(預設的數值遞增機制應付不了了) -
Any 型別相當於局部的型別檢查開關,這在 TypeScript 與 JavaScript 程式碼並存的專案中很有意義
-
Void 型別的變數也是合法的,約束值只能是
undefined或null -
Null、Undefined 和 Never 是其他型別的子型別,因此可以賦值給任何其他型別變數(例如
let str: string = null也是合法的) -
其他任何型別都不可以賦值給 Never 型別,即便是 Any 也不行
-
Never 型別的變數也是合法的,此時 Never 可以用作型別保護(例如
declare const name: never;避免隱式存取window.name)
P.S. 特殊的,建議開啟 --strictNullChecks 選項,此時 Undefined 和 Null 只允許賦值給 Void 以及各自對應的型別
P.S. 關於 Never 作為型別保護的應用,見 Improve type safety of name global variable
三. 型別斷言
可以透過型別斷言告知 TypeScript 編譯器某個值的確切型別:
Type assertions are a way to tell the compiler “trust me, I know what I’m doing.”
類似於其他語言裡的強制型別轉換(type casting),區別在於型別斷言只是編譯時的,不像型別轉換一樣具有執行時影響:
A type assertion is like a type cast in other languages, but performs no special checking or restructuring of data. It has no runtime impact, and is used purely by the compiler.
有兩種語法格式,分別是 <type> 和 as type ,例如
let someValue: any = "this is a string";
// <type>
let strLength: number = (<string>someValue).length;
// as type
let strLength: number = (someValue as string).length;
兩種方式等效,但在 JSX 中只能用 as type (角括號語法與 JSX 語法衝突)
四. 常用技巧
存取列舉 key
實際上, TypeScript 列舉型別建立了 key-value 的雙向索引,例如:
enum Color {Red = 1, Green, Blue}
// 对应的JavaScript为
var Color;
(function (Color) {
Color[Color["Red"] = 1] = "Red";
Color[Color["Green"] = 2] = "Green";
Color[Color["Blue"] = 3] = "Blue";
})(Color || (Color = {}));
// 得到
// {1: "Red", 2: "Green", 3: "Blue", Red: 1, Green: 2, Blue: 3}
因此,一個有意思的技巧是根據列舉值存取 key :
let colorName: string = Color[2];
// 此时,colorName为'Green'
修改 global
Any 型別用來繞過編譯時型別檢查,因此可以用來修改一些不能改的東西,例如:
window.customFunction = myCustomFunction;
編譯報錯:
Property 'customFunction' does not exist on type 'Window'.
可以透過 any 型別繞過:
const globalAny: any = window;
globalAny.customFunction = myCustomFunction;
或者等效的型別斷言:
(<any> window).customFunction = myCustomFunction;
// 或
(window as any).customFunction = myCustomFunction;
暫無評論,快來發表你的看法吧