TypeScript 簡介
-
TypeScript 是 JavaScript 的一個超集,支持 ECMAScript 6 標准(ES6 教程)。
-
TypeScript 由微軟開發的自由和開源的編程語言。
-
TypeScript 設計目標是開發大型應用,它可以編譯成純 JavaScript,編譯出來的 JavaScript 可以運行在任何瀏覽器上。
JavaScript 與 TypeScript 的區別
TypeScript 是 JavaScript 的超集,擴展了 JavaScript 的語法,因此現有的 JavaScript 代碼可與 TypeScript 一起工作無需任何修改,TypeScript 通過類型注解提供編譯時的靜態類型檢查。
TypeScript 可處理已有的 JavaScript 代碼,並只對其中的 TypeScript 代碼進行編譯。
TypeScript 優缺點
優點
1. 可維護性強
- 類型系統實際上是最好的文檔,大部分的函數看看類型的定義就可以知道如何使用了
- 可以在編譯階段就發現大部分錯誤,這總比在運行時候出錯好
- 增強了編輯器和 IDE 的功能,包括代碼補全、接口提示、跳轉到定義、重構等
2. 包容性強
- TypeScript 是 JavaScript 的超集,
.js
文件可以直接重命名為.ts
即可 - 即使不顯式的定義類型,也能夠自動做出類型推論
- 可以定義從簡單到復雜的幾乎一切類型
- 即使 TypeScript 編譯報錯,也可以生成 JavaScript 文件
- 兼容第三方庫,即使第三方庫不是用 TypeScript 寫的,也可以編寫單獨的類型文件供 TypeScript 讀取
3. 社區活躍
- 大部分第三方庫都有提供給 TypeScript 的類型定義文件
- Google 開發的 Angular2 就是使用 TypeScript 編寫的
- TypeScript 擁抱了 ES6 規范,也支持部分 ESNext 草案的規范
缺點
任何事物都是有兩面性的,我認為 TypeScript 的弊端在於:
- 有一定的學習成本,需要理解 接口(Interfaces)、泛型(Generics)、類(Classes)、枚舉類型(Enums)等前端工程師可能不是很熟悉的概念
- 短期可能會增加一些開發成本,畢竟要多寫一些類型的定義,不過對於一個需要長期維護的項目,TypeScript 能夠減少其維護成本
- 集成到構建流程需要一些工作量
- 可能和一些庫結合的不是很完美
安裝
通過 npm 全局安裝:npm install -g typescript
通過 yarn 全局安裝:yarn global add typescript
查看版本號:tsc -v
TypeScript 在全局安裝后,我們可以在任意位置使用 tsc
命令,tsc
命令負責編譯 TypeScript 文件為 JavaScript 文件。
TypeScript 基礎類型
1. 數字
和 JavaScript 一樣,TypeScript 里的所有數字都是浮點數。 這些浮點數的類型是 number
。
除了支持十進制和十六進制字面量,TypeScript 還支持 ECMAScript 2015 中引入的二進制和八進制字面量。
let binaryLiteral: number = 0b1010; // 二進制
let octalLiteral: number = 0o744; // 八進制
let decLiteral: number = 6; // 十進制
let hexLiteral: number = 0xf00d; // 十六進制
2. 字符串
使用 string
表示文本數據類型,使用單引號(')或雙引號(")來表示字符串類型。反引號(`)來定義多行文本和內嵌表達式
let name: string = "blog";
let years: number = 5;
let words: string = `您好,今年是 ${ name } 發布 ${ years + 1} 周年`;
3. 布爾值
最基本的數據類型就是簡單的 true/false 值,在JavaScript 和 TypeScript 里叫做 boolean
let flag: boolean = true;
4. 數組
TypeScript 像 JavaScript 一樣可以操作數組元素。 有兩種方式可以定義數組:
// 在元素類型后面加上[]
let arr: number[] = [1, 2];
// 或者使用數組泛型
let arr: Array<number> = [1, 2];
5. 函數
// 在函數上直接聲名 參數any 和 返回值boolean
function isFalsy(val: any): boolean {
return val === 0 ? false : !val;
}
// 函數沒有返回值則使用void
function hello(str: string): void {
alert(str);
}
6. any
聲明為 any
的變量可以賦予任意類型的值,意味着不做任何類型檢查,失去TS的意義 (盡量避免使用)
let x: any = 1; // 數字類型
x = 'hello'; // 字符串類型
x = false; // 布爾類型
7. void
用於標識方法返回值的類型,表示該方法沒有返回值或返回 undefined
function warnUser(): void {
console.log("This is my warning message");
}
8. null 和 undefined
null
-
在 JavaScript 中 null 表示 "什么都沒有"
-
null是一個只有一個值的特殊類型。表示一個空對象引用
-
用 typeof 檢測 null 返回是 object
undefined
-
在 JavaScript 中, undefined 是一個沒有設置值的變量。
-
typeof 一個沒有值的變量會返回 undefined。
-
Null 和 Undefined 是其他任何類型(包括 void)的子類型,可以賦值給其它類型,如數字類型,此時,賦值后的類型會變成 null 或 undefined。
let x: number;
x = 1; // 運行正確
x = undefined; // 運行錯誤
x = null; // 運行錯誤
上面的例子中變量 x 只能是數字類型。如果一個類型可能出現 null 或 undefined, 可以用 |
來支持多種類型,示例代碼如下:
let x: number | null | undefined;
x = 1; // 運行正確
x = undefined; // 運行正確
x = null; // 運行正確
9. object
object表示非原始類型,也就是除 number,string,boolean,symbol,null 或 undefined 之外的類型
function hello(obj: object | null): void {
console.log(obj);
}
hello({ name: 'zhangsan' });
hello(null);
10. 元組
Tuple
類型允許表示一個已知元素數量和類型的數組,各元素的類型不必相同
let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; // Error
x[2] = 'world'; // OK, 字符串可以賦值給(string | number)類型
x[3] = true; // Error, 布爾不是(string | number)類型
11. 枚舉
enum
類型是對JavaScript標准數據類型的一個補充。 像C#等其它語言一樣,使用枚舉類型可以為一組數值賦予友好的名字
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
12. never
never
是其它類型(包括 null 和 undefined)的子類型,代表從不會出現的值。這意味着聲明為 never 類型的變量只能被 never 類型所賦值,在函數中它通常表現為拋出異常或無法執行到終止點(例如無限循環),示例代碼如下:
let x: never;
let y: number;
// 運行錯誤,數字類型不能轉為 never 類型
x = 123;
// 運行正確,never 類型可以賦值給 never類型
x = (()=>{ throw new Error('exception')})();
// 運行正確,never 類型可以賦值給 數字類型
y = (()=>{ throw new Error('exception')})();
// 返回值為 never 的函數可以是拋出異常的情況
function error(message: string): never {
throw new Error(message);
}
// 返回值為 never 的函數可以是無法被執行到的終止點的情況
function loop(): never {
while (true) {}
}
TypeScript 類型推論
理論上來說在我們聲明任何變量的時候都需要聲明類型(包括普通變量、函數、組件、react hook 等),聲明函數、組件、react hook 等需要聲明參數和返回值的類型
但是在很多情況下,TS可以幫助我們自動推斷,我們就不用聲明了,比如:
1. 變量的類型推論
這里雖然沒有顯示聲明,但是ts自動推斷這個變量是 string 類型:
可以看到,定義變量 str 時並沒有指定它的類型,而是直接賦值一個字符串,當再給它賦一個數值時就會報錯。這里 typescript 就根據我們賦給 str 的值的類型,推斷出我們的 str 的類型,是字符串類型,所以不可以將數值類型賦給它。
這個就是最基本的類型推論,根據右側的值推斷左側變量的類型。
2. 返回值的類型推論
ts自動推斷函數返回值這是個 number 類型:
3. 多類型聯合
當我們定義一個數組或者元組這種包含多個元素的值的時候,多個元素可以有不同的類型,這時候 typescript 會將多個類型合並起來,組成一個聯合類型,例如:
const arr = [1, 'a']
arr.push(false) // error,類型“false”的參數不能賦給類型“string | number”的參數
此時的 arr 的元素被推斷為 string | number,也就是元素可以是 string 類型也可以是 number 類型,除此之外的類型是不可以的。
再一個例子:
let value = Math.random() * 10 > 5 ? 123 : 'abc'
value = false // error,不能將類型“false”分配給類型“string | number”。
value 的值是隨機的,但是只能是 string 或者 number,它的類型被推斷出是 string | number,所以不能賦值 false。
4. 上下文類型
前面講的例子都是根據 = 符號右邊值的類型,推斷出左側變量的類型。現在還有一種是根據左側的類型推斷右側的類型,這就是上下文類型。官網的例子:
window.onmousedown = function (mouseEvent) {
console.log(mouseEvent.abc); // error,mouseEvent 上不存在屬性 abc
};
表達式左側是 window.onmousedown
(鼠標按下時發生事件),因此 TypeScript 會推斷賦值表達式右側函數的參數是事件對象,且是 MouseEvent。在回調函數中使用 mouseEvent 的時候,你可以訪問鼠標事件對象的所有屬性和方法,當訪問不存在屬性的時候,就會報錯。