標籤:

TypeScript入門

TypeScript是由微軟開發,2012年10月份發布第一個版本,代碼開源,託管在GitHub

它的特點有:

1. es6支持:TypeScript是JavaScript的擴展,它沿用了es6的一些新特性。

2. 類型檢查:TypeScript提供了靜態語言強類型支持,增加了靜態編譯時的類型檢查(也可以忽略),兼容動態語言弱類型的語法,因此TypeScript和JavaScript可以共存,最終被編譯成純粹的javascript。另外有了類型定義後,配合支持TypeScript的編輯器,寫代碼是一種很好的體驗,函數的定義會自動提示出來,錯誤也會自動提示。


本文從類型系統出發,介紹了TypeScript的類型定義系統,下面開始學習TypeScript

第一部分:類型系統

1. 原始類型

number,string,boolean,null,undefined,symbol(ES6)n

  • ES6支持:字元串類型支持ES6的模板字元串
  • 特殊類型:undefined 和 null 是所有類型的子類型

2. any類型

  • any類型:如果變數聲明但未賦值時未指定類型,默認為any類型,變數被定義成any類型後,可以訪問任意屬性和方法,不會被類型檢查
  • 延伸:

- 類型推斷:如果變數聲明的時候有賦值,則會根據值的類型推斷出一個具體的類型

- 聯合類型:多種類型之間可以組合

let num: number = 8; //指出明確類型nttnlet anything: any = 8; //等價於 let anythingntt anything = I want to be string; //oknt anything.getName(); //編譯oknttnlet something = you define me; //等價於 something: stringsomething = 8; //類型推斷為string,賦值number時,編譯報錯ntt nlet numOrStr: number | string; //聯合類型nt numOrStr = 7; nt numOrStr = I can be string too; n

3. 對象的類型

tTypeScript中類型檢查關注值的形狀,介面(interface)作為一種規範,可用來定義形狀和約束,描述對象的類型

  • 普通屬性:屬性描述支持可選屬性(?)和只讀屬性(readonly)
  • 字元串索引屬性:當為介面添加任意屬性時,此時介面的確定屬性和可選屬性的類型必須是任意屬性類型的子屬性
  • 數字索引屬性:可以描述一個數組對象,具體見 4.數組的類型
  • 函數類型屬性:除了描述普通的屬性,還可以描述函數類型,具體見 5.函數的類型
  • 延伸:介面的其他特性

- 泛型介面:為介面傳入一個或多個類型變數來提高介面的通用性,這樣的介面稱為泛型介面,使用的時候需要定義泛型的類型

t - 介面繼承介面:介面可以繼承介面,相互擴展

t - 介面繼承類:不同於Java等語言中介面的作用,TypeScript里介面可以繼承類,當介面繼承一個類類型時,它會繼承類的所有成員但不包括其實現,當介面繼承了一個具有private或protected的類時,這個介面就只能被這個類或它的子類去實現,原理見 7.類類型

tinterface Person { //首字母大寫nttname: string;nttage: number; ntt[propNamr: string]: stringnt}ntntlet individual: Person = {nttname: Alice,nttage: 20, nttgender:femalent} t//age的類型number不是string的子類,編譯無法通過ntnt//介面約束數組ntinterface stringArray {n readonly [index: number]: string;nt}ntnt/* ----------------------------------------- */nt// 泛型介面ntinterface Person<T> {ntt[propName: string]: Tnt}ntlet individual: Person<string> = {nttname:Tomnt}ntlet individual2: Person<number> = {nttage:20nt}n

4. 數組的類型

t合併相同類型的對象叫數組,合併不同類型的對象叫元祖(Tuple),數組用類型[]或者 Array<類型>定義,介面也可以用來定義數組或元祖

tlet array1: number[] = [1,2,3];ntlet array2: Array<number> = [1,2,3];ntlet tuple = [string,number]ntntinterface NumberArray {n [index: number]: number;nt}ntntinterface NumberArray {n 0: number;n 1: string;nt}n

5. 函數的類型

  • 對函數的輸入和輸出定義類型

- 如果函數沒有輸出時,使用關鍵字void

- 如果永遠沒有返回,使用關鍵字never,如

function error(message:String): never { throw new Error(message)}n

- 支持定義泛型函數

  • 一等公民函數:當一個變數為函數類型,用(輸入)=> (輸出)表示函數類型定義,可以在介面中定義函數類型,描述函數的形狀
  • 函數參數

t - 可選參數:當定義參數和傳入參數不一致時,需明確指出可選參數,並且可選參數必須放在必須參數的後面

t - 默認參數:可以為參數指定初始值(ES6)

t - 剩餘參數:同ES6,用...rest獲取剩餘參數

  • 函數重載

t - 函數名相同,參數個數或類型不一樣,和返回值類型無關。

t - 實現同一個功能的函數可以取相同的名字,還可以清晰的告訴調用者傳入什麼參數得到什麼結果

function add(x:number,y:number): number{nt return x + y nt}nt//將函數賦值給一個變數,此時為變數定義函數類型ntlet myAdd: (x:number,y:number) => number = addnt//用介面定義函數的類型ntinterface AddFunc {nt (x:number,y:number): number nt}ntlet myAdd: AddFunc = add;n

6. 枚舉類型(Enum)

t枚舉類型是一種名稱數值集,默認情況下,枚舉成員索引從0開始遞增,它也支持手動賦值,枚舉索引和枚舉值具有雙向映射關係

enum Directions {Up,Down,Left,Right};ntlet d: Directions = Directions.Up;ntconsole.log(Directions.Up); //0ntconsole.log(Directions[0]) //Upn

7. 類類型

tTypeScript除了實現ES6中類的所有功能之外,還添加了新用法,給類加上類類型類似於介面

  • 增加了public,private,protected,readonly關鍵字修飾的訪問許可權,成員都默認為 public,當成員被標記成private時,它就不能在聲明它的類的外部訪問,protected修飾符與private修飾符的行為很相似,但有一點不同,protected成員在派生類中仍然可以訪問。readonly關鍵字將屬性設置為只讀的,只讀屬性必須在聲明時或構造函數里被初始化。
  • 提供了抽象類(abstract)
  • 類可以實現介面(implements),使一個類去符合某種契約,介面用來描述類的公共部分
  • 類似泛型介面,也可以定義泛型類

8. type創建別名

type可以為上述類型創建別名,為對象創建別名的作用類似介面,但不具備介面可以繼承和實現的特點,所以不要用type代替介面

  • 原始類型 `type a = string`
  • 函數類型 `type b = () => string`
  • 聯合類型 `type Alias = a | b;`
  • 字元字面量類型 `type Easing = "ease-in" | "ease-out" | "ease-in-out"; `
  • 泛型 `type Container<T> = { value: T };`

上述是TypeScript的類型定義,對於any,聯合類型,或泛型這些不確切的類型,我們不可以安全的操作它的屬性或方法,為此TypeScript提供了類型斷言類型約束規範,對定義了any類型或聯合類型的變數進行類型斷言,告訴編譯器確切的類型,然後才能判斷某個屬性是否存在,例如,想要獲取length屬性,需要斷言為string類型,其語法為`<類型>值`或者`值 as 類型`,在JSX中使用as語法。對於泛型,我們可以對其進行泛型約束,通過繼承(extends)的方式,泛型繼承介面使之符合介面的形狀,多個類型參數之間也可以實現繼承,來實現參數之間的約束

//類型斷言nfunction getLength(something: String | number): number {ntif((something as string).length) {nt return (something as string).lengthnt} else {nt return something.toString().lengthnt}n}nn//類型約束ninterface Length {n length: numbern} n//約束泛型T必須包含length屬性nfunction getLength<T extends Length>(something:T): number {n return something.lengthn}ngetLength(123); //123沒有length屬性,編譯報錯n

TypeScript的關鍵之一是type,我們定義類型,當我們要使用第三方庫時,就需要使用它的聲明文件,聲明文件以`.d.ts`為後綴,用`declare`關鍵字定義,為了便於管理,所有的類型被發布到npm @types scope下,使用npm安裝對應的聲明模塊即可,例如`npm install @types/react`

內置對象如`Error`,`Date`,`Document`,`NodeList`等可以直接作為TypeScript的類型定義使用,它們在TypeScript核心庫的定義文件中定義好了

第二部分:在react項目中使用TypeScript

1. 在項目里安裝 TypeScript 編譯器,並在工程根目錄運行tsc --init,自動產生tsconfig.json文件。初始化得到的tsconfig.json,增加"allowJs": true,"jsx": "react" 選項,詳細配置參考TypeScript 官方文檔。

npm install --save-dev typescriptntsc --initn

2. 增加react聲明文件,react和react的聲明文件的版本需一致

npm install --save-dev @types/react @types/react-dom @types/react-reduxn

3. 配置webpack,可參考Webpack & Typescript,增加ts的loader,如awesome-typescript-loader。同時也添加了 resolve.extensions 來告訴 webpack 在解析查找 TypeScript 模塊時該檢索哪些文件擴展名。

npm install --save-dev awesome-typescript-loadern

module: {n rules: [n {n test: /.(ts|tsx)$/,n exclude: /node_modules/,n loader: "awesome-typescript-loader",n }n ]n },n resolve: {n extensions: [".tsx", ".ts", ".js"".jsx"]n },n

4. 新項目可以參考TypeScript-React-Starter

參考鏈接

TypeScript入門教程

TypeScript中文手冊

TypeScript 快速入門

推薦閱讀:

是時候再給TypeScript一次機會了【譯】
你所不知道的 Typescript 與 Redux 類型優化
推斷函數返回值的類型
Hello RxJS
有哪些公司在使用或者準備使用Angular2?

TAG:TypeScript |