【你應該掌握的】深刻淺出typescript

團隊:skFeTeam  本文做者:高揚css

介紹

TypeScript是一種由微軟開發的開源、跨平臺的編程語言。它是JavaScript的超集,最終會被編譯爲JavaScript代碼。html

TypeScript能夠解決JavaScript弱類型和沒有命名空間,難以模塊化的問題,同時也加強了代碼的可讀性,在團隊協做和大型項目中體現出更大的優點。前端

本文將從「基礎用法、高階用法、模塊、react項目實踐中的應用」四個方向展開文章,方便你們理解,都會備註列子、codesandbox上的遠程代碼。react

基礎用法

1.變量類型

代碼示例 src/components/baseVar.tsxgit

  • TypeScript提供與JavaScript幾乎相同的數據類型(布爾值boolean,字符串string,數字number,數組[],元組),此外還提供了枚舉enum類型。
  • 當不肯定變量的數據類型或者數據類型會在代碼運行過程當中變化時,使用any來標記這些變量,使它們經過編譯階段的檢查。
  • object表示原始類型之外的類型,即number,string,boolean,symbol,null,undefined之外的類型。
  • void用於表示沒有任何類型,一般用於方法沒有返回值時。void類型的變量只能賦值undefined或者null。
  • nullundefined各自的類型分別爲null和undefined,並無太大用處。
  • never表示永不存在的類型或方法沒法達到終點,當代碼中拋出異常或者while(true)時可能會用到。
  • symbol(自ECMAScript 2015起的新的原生類型),不可改變且惟一,經過Symbol函數構造。TypeScript中內置了一些symbols表示語言內部行爲。
  • 類型斷言: as / <> / !
    當TypeScript沒法推斷出對象類型但開發者能夠肯定時,能夠經過類型斷言來顯式表達變量類型。

在實際使用過程當中,原始類型和any以及類型斷言較爲經常使用,object,void,null,undefined,never,symbol不常用。github

經常使用的變量類型及聲明

2.接口

代碼示例 src/components/interface.tsxtypescript

相較於基礎類型而言,接口用於更具體地聲明更加複雜的對象結構,關鍵字爲interface編程

聲明方法

聲明方法代碼示例1
聲明方法代碼示例2
方法體內的入參 名稱不要求與接口聲明中 徹底一致

聲明變量

聲明變量代碼示例
變量聲明中:

  • readonly關鍵字表示屬性只讀,不可修改。
  • ?表示可選屬性,便可以不傳該字段,可選參數在必傳參數後面。
  • [propName: string]:any能夠匹配到除前面已聲明屬性外的全部字符串名稱的屬性,如:sex: boolean, address: any, email: string等,可用於不肯定入參中是否還包含其餘屬性時。

方法的屬性排序不要求與接口聲明徹底一致數組

設置默認值

默認值代碼示例
默認值屬於可選參數的一種,但默認值不要求在必選參數以後。
當默認值在可選參數前時,須要傳入undefined來獲取默認值。

剩餘參數

當方法中傳參數量不必定或須要批量操做入參時,能夠經過剩餘參數來操做多個參數。 編程語言

剩餘參數代碼示例

3.簡單的高級類型

代碼示例 src/components/types.tsx

交叉類型(&)

交叉類型是將多個類型合併爲一個類型,包含全部所需類型的全部屬性。

交叉類型代碼示例

聯合類型(|)

聯合類型表示一個值能夠是幾個類型之一。

聯合類型代碼示例1
若是一個值是聯合類型,咱們 只能訪問全部類型的共有成員
聯合類型代碼示例2

字符串/數字字面量類型

字符串字面量類型容許指定字符串類型的固定值。
數字字面量類型容許指定數字類型的固定值。

字面量類型代碼示例

4.迭代器

代碼示例 src/components/for.tsx
由於一些內置的類型Map,Array等實現了各自的Symbol.iterator,所以他們都是可迭代的。 (Symbol.iterator方法,被for-of語句調用。返回對象的默認迭代器)
如下語句可用於遍歷可迭代對象。

for...of...

(當生成目標爲ES5或ES3,迭代器只容許在Array類型上使用。 在非數組值上使用 for..of語句會獲得一個錯誤,就算這些非數組值已經實現了Symbol.iterator屬性。)

for-of代碼示例

for...in...

for-in代碼示例

高階用法

1.泛型

代碼示例 src/components/identity.tsx
泛型,指不預先肯定的數據類型,在使用時纔去肯定。這裏的使用時,不是指代碼運行時。

泛型的本質是將類型參數化,這種參數化的類型可使用在類、接口及方法中成爲泛型類、泛型接口、泛型方法。

泛型是用於建立可複用代碼組件的重要工具,使得代碼片斷能夠被多種數據類型使用。

考慮當一個方法有多種可能類型的入參,或者一個變量有多種可能類型的賦值時,經過聯合類型列出全部可能的類型有時候是不現實或者繁雜的。固然,咱們也能夠將其定義爲any類型來經過編譯階段的檢查,但帶來的問題是類型準確性的丟失,調試時也沒法看到完整的參數信息。正是所以,TypeScript並不推薦使用any,由於使用any與不引入TypeScript是沒有太大區別的。

泛型可用於解決這類問題。

書寫泛型接口或方法或類時,咱們經過一個類型變量來捕獲參數的類型,顯示在**尖括號<>**中,命名隨意,一般以大寫字母表明

在實際調用該方法時,給類型變量賦予實際的類型,如string,array,number,boolean等;如不賦值具體類型,則TypeScript經過類型推斷來檢查代碼。

泛型代碼示例
在示例代碼中,func1,func2,func3返回與入參類型一致的出參。< T > < U >捕獲入參的類型,並用於規範方法的出參。

泛型約束

有時,咱們對方法的入參雖然不限制類型,但仍然指望他具有某個屬性或者知足某些限制,此時咱們可使用extends關鍵字繼承接口來給泛型增長約束。

泛型約束代碼示例
示例中func4與func5的區別在於,func5中T extends Leng。當給T增長了約束必須具有length屬性時,arg就被限制了類型不能夠是number,而且arg.length也不存在undefined的狀況。

2.複雜的高級類型

區分類型

代碼示例 src/components/types.tsx
當出現**聯合類型(Person | Worker)**時,有時咱們須要調用非共有屬性,此時須要進一步確認當前變量究竟屬於哪一個類型。TypeScript提供了一些方法進行類型區分。

  • typeof / instanceof
    typeof與instanceof能夠被TypeScript識別爲原始類型的類型保護,咱們能夠藉此進行原始類型的區分。
    typeof代碼示例
  • 用戶自定義的類型保護
    當須要對非原始類型進行判斷時,用戶能夠自定義一個類型保護函數,返回值是一個類型謂詞,類型謂詞形式爲paramName is TypeName

用戶自定義類型保護代碼示例
該示例中 isWorker就是一個類型保護函數,用於判斷入參是不是Worker類型,類型謂詞是 p is Worker

  • 類型斷言
    若是開發人員肯定當前變量在上下文是什麼類型,也能夠經過類型斷言as/<>顯式代表當前變量類型來經過TypeScript的檢查。

類型斷言類型保護代碼示例
在實際開發需求中,咱們也常常會遇到某些參數或變量可能爲null/undefined的狀況,此時調用某些方法就會產生報錯。

咱們可使用類型斷言標記!後綴手動去除null和undefined。

去除null代碼示例

類型別名(Type)

代碼示例 src/components/types.tsx

類型別名會給類型(包括原始類型)起一個新的名字。給原始類型取別名能夠加強代碼可讀性,相似於文檔,但較少使用。類型別名更多地使用於非原始類型的狀況。

類型別名(type)與接口(interface)很是類似,但存在如下幾點區別:

  • 接口建立了新的名字,但類型實際上沒有
  • 接口能夠被extends和implements,但類型不支持
  • 若是須要使用聯合類型或交叉類型,這時會選擇類型別名
    類型別名代碼示例

可辨識聯合

代碼示例 src/components/union.tsx

可辨識聯合也稱標籤聯合或代數數據類型。它是將單例類型,聯合類型,類型保護和類型別名合併起來建立的,具備如下三個特徵:

  • 具備普通的單例類型屬性 - 是該數據類型可辨識的特徵
  • 一個數據類型包含了多種類型的聯合
  • 該屬性上的類型保護 (能夠經過單例類型屬性進行類型區分)

(單例類型即只有一個實例的類型,可看做是僅有一個值的字符串/數字字面量類型)

可辨識聯合代碼示例

索引類型

代碼示例 src/demos/tk.tsx

使用索引類型,TypeScript能夠檢查使用了動態屬性名的代碼。一般用於對象的不常規處理。

索引類型查詢操做符keyof能夠獲取對象上全部屬性名,**索引訪問操做符K[T]**能夠獲取對象上特定屬性的類型。

索引類型代碼示例
在示例代碼中,因爲K extends keyof T,所以K的取值是有限的,等價於K : "id" | "age" | "school" | "location",而且K的取值隨着T的key變化而變化。

映射類型

代碼示例 src/demos/tk.tsx

映射類型是TypeScript提供的一種以相同方式從舊的類型中轉換出新的類型的方式,例如將全部屬性轉換爲只讀屬性或可選屬性。

TypeScript集成了一些已實現的映射類型。

映射類型代碼示例
固然開發者也能夠根據業務需求利用索引類型等方式實現自定義的映射類型。

3.模塊

代碼示例 src/module/*

從ECMAScript 2015開始,JavaScript引入了模塊的概念。TypeScript也沿用這個概念。

導出

任何聲明(好比變量,函數,類,類型別名或接口)、語句都可以經過添加export關鍵字來導出。

導出時能夠經過as關鍵字來重命名。

導出代碼示例
當一個模塊包含多個模塊時,能夠經過export *來導出全部模塊。

導出全部模塊代碼示例
默認導出

每一個模塊均可以有至多一個默認導出,用export default來標記。

導入

使用import關鍵字導入其餘模塊中導出的內容,使用as關鍵字重命名,使用*導入路徑下全部導出內容。

導入代碼示例
當導入默認導出的模塊時,導入時能夠自由命名。

默認導入代碼示例

直接import "xxx"也是一種導入方式,可是有反作用的導入。導入文件會對整個項目生效,須要謹慎使用。一般僅在項目入口文件裏導入全局css時會用到。

相對導入和非相對導入

根據模塊引用是相對的仍是非相對的,TypeScript會以不一樣的方式解析導入模塊。

以/,./或../開頭的被認爲是相對導入。 例如:

  • import Entry from "./components/Entry";
  • import { DefaultHeaders } from "../constants/http";
  • import "/mod";

全部其它形式的導入都被看成非相對導入。 例如:

  • import { Component } from "@angular/core";

export = 和 import module = require()

爲了支持CommonJS和AMD中的exports,TypeScript提供了export = 的導入聲明。

當使用export =導出模塊時,必需要使用import moduleName = require("xxxx")來導入。

現有React + Antd前端項目中經常使用的一些TS

1.Form表單

代碼示例 src/template/form.tsx

form表單

2.Table表格

代碼示例 src/template/table.tsx

table表格

參考文章

想了解skFeTeam更多的分享文章,能夠點這裏,謝謝~

相關文章
相關標籤/搜索