泛型是程序設計語言中的一種風格或范式,相當于類型模板,允許在聲明類、接口或函數等成員時忽略類型,而在未來使用時再指定類型,其主要目的是為它們提供有意義的約束,提升代碼的可重用性。
## 一、泛型參數
當一個函數需要能處理多種類型的參數和返回值,并且還得約束它們之間的關系(例如類型要相同)時,就可以采用泛型的語法,如下所示。
~~~
function send<T>(data: T): T {
return data;
}
~~~
  函數名稱后面跟了,其中把T稱為泛型參數或泛型變量,表示某種數據類型。注意,T只是個占位符,可以命名的更含語義,例如TKey、TValue等。在使用時,既可以指定類型,也可以利用類型推論自動確定類型,如下所示。
~~~
send<number>(10); //指定類型
send(10); //類型推論
~~~
  當需要處理T類型的數組時,可以像下面這么寫。
~~~
function send<T>(data: T[]): T[] {
return data;
}
send<number>([1, 2, 3]);
~~~
  當指定一個泛型函數的類型時,需要包含泛型參數,如下所示,其中泛型參數和函數參數的名稱都可與定義時的不同。
~~~
let func: <U>(data: U) => U = send;
~~~
  泛型參數還支持傳遞多個,只需在聲明時增加類型占位符即可。在下面的示例中,將T和U合并成了一個元組類型,還有許多其它用法,將在后面講解。
~~~
function send<T, U>(data: [T, U]): [T, U] {
return data;
}
send<number, string>([1, "a"]);
~~~
## 二、泛型接口
  在接口中,可利用泛型來約束函數的結構,如下所示,接口中聲明的調用簽名包含泛型參數。
~~~
interface Func {
<T>(str: T): T;
}
function send<T>(str: T): T {
return str;
}
let fn: Func = send;
~~~
  泛型參數還可以作為接口的一個參數存在,即把用尖括號包裹的泛型參數移到接口名稱之后,如下所示。
~~~
interface Func<T> {
(str: T): T;
}
function send<T>(str: T): T {
return str;
}
let fn: Func<string> = send;
~~~
  當把Func接口作為類型使用時,需要向其傳入一個類型,例如上面賦值語句中的string。
## 三、泛型類
  泛型類與泛型接口類似,也是在名稱后添加泛型參數,如下所示,其中send屬性中的“=>”符號不表示箭頭函數,而是用來定義方法的返回值類型。
~~~
class Person<T> {
name: T;
send: (data: T) => T;
}
~~~
  在實例化泛型類時,需要為其指定一種類型,如下所示。
~~~
let person = new Person<string>();
person.send = function(data) {
return data;
}
~~~
  注意,類的靜態部分不能使用泛型參數。
## 四、泛型約束
  在使用泛型時,由于事先不清楚參數的數據類型,因此不能隨意調用它的屬性或方法,甚至無法對其使用運算符。在下面的示例中,訪問了data的length屬性,但由于編譯器無法確定它的類型,因此就會報錯。
~~~
function send<T>(data: T): T {
console.log(data.length);
return data;
}
~~~
  TypeScript允許為泛型參數添加約束條件,從而就能調用相應的屬性或方法了,如下所示,通過extends關鍵字約束T必須是string的子類型。
~~~
function send<T extends string>(data: T): T {
console.log(data.length);
return data;
}
~~~
  在添加了這個約束之后,send()函數就無法接收數字類型的參數了,如下所示。
~~~
send("10"); //正確
send(10); //錯誤
~~~
**1)創建類的實例**
  在使用泛型創建類的工廠函數時,需要聲明T類型擁有構造函數,如下所示。
~~~
class Programmer { }
function create<T>(ctor: {new(): T}): T {
return new ctor();
}
create(Programmer);
~~~
  用“{new(): T}”替代原先的類型占位符,表示可以被new運算符實例化,并且得到的是T類型,另一種相同作用的寫法如下所示。
~~~
function create<T>(ctor: new()=>T): T {
return new ctor();
}
~~~
**2)多個泛型參數**
  在TypeScript中,多個泛型參數之間也可以相互約束,如下所示,創建了基類Person和派生類Programmer,并將create()函數中的T約束為U的子類型。
~~~
class Person { }
class Programmer extends Person { }
function create<T extends U, U>(target: T, source: U): T {
return target;
}
~~~
  當傳遞給create()函數的參數不符合約束條件時,就會在編譯階段報錯,如下所示。
~~~
create(Programmer, Person); //正確
create(Programmer, 10); //錯誤
~~~
*****
> 原文出處:
[博客園-TypeScript躬行記](https://www.cnblogs.com/strick/category/1561745.html)
[知乎專欄-TypeScript躬行記](https://zhuanlan.zhihu.com/pwts2019)
已建立一個微信前端交流群,如要進群,請先加微信號freedom20180706或掃描下面的二維碼,請求中需注明“看云加群”,在通過請求后就會把你拉進來。還搜集整理了一套[面試資料](https://github.com/pwstrick/daily),歡迎瀏覽。

推薦一款前端監控腳本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不僅能監控前端的錯誤、通信、打印等行為,還能計算各類性能參數,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、擴展運算符和剩余參數
- 3、解構
- 4、模板字面量
- 5、對象字面量的擴展
- 6、Symbol
- 7、代碼模塊化
- 8、數字
- 9、字符串
- 10、正則表達式
- 11、對象
- 12、數組
- 13、類型化數組
- 14、函數
- 15、箭頭函數和尾調用優化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、類
- 21、類的繼承
- 22、Promise
- 23、Promise的靜態方法和應用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基礎實踐
- 3、WebRTC視頻通話
- 4、Web音視頻基礎
- CSS進階
- 1、CSS基礎拾遺
- 2、偽類和偽元素
- 3、CSS屬性拾遺
- 4、浮動形狀
- 5、漸變
- 6、濾鏡
- 7、合成
- 8、裁剪和遮罩
- 9、網格布局
- 10、CSS方法論
- 11、管理后臺響應式改造
- React
- 1、函數式編程
- 2、JSX
- 3、組件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表單
- 8、樣式
- 9、組件通信
- 10、高階組件
- 11、Redux基礎
- 12、Redux中間件
- 13、React Router
- 14、測試框架
- 15、React Hooks
- 16、React源碼分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基礎
- 4、webpack進階
- 5、Git
- 6、Fiddler
- 7、自制腳手架
- 8、VSCode插件研發
- 9、WebView中的頁面調試方法
- Vue.js
- 1、數據綁定
- 2、指令
- 3、樣式和表單
- 4、組件
- 5、組件通信
- 6、內容分發
- 7、渲染函數和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、數據類型
- 2、接口
- 3、類
- 4、泛型
- 5、類型兼容性
- 6、高級類型
- 7、命名空間
- 8、裝飾器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系統和網絡
- 3、命令行工具
- 4、自建前端監控系統
- 5、定時任務的調試
- 6、自制短鏈系統
- 7、定時任務的進化史
- 8、通用接口
- 9、微前端實踐
- 10、接口日志查詢
- 11、E2E測試
- 12、BFF
- 13、MySQL歸檔
- 14、壓力測試
- 15、活動規則引擎
- 16、活動配置化
- 17、UmiJS版本升級
- 18、半吊子的可視化搭建系統
- 19、KOA源碼分析(上)
- 20、KOA源碼分析(下)
- 21、花10分鐘入門Node.js
- 22、Node環境升級日志
- 23、Worker threads
- 24、低代碼
- 25、Web自動化測試
- 26、接口攔截和頁面回放實驗
- 27、接口管理
- 28、Cypress自動化測試實踐
- 29、基于Electron的開播助手
- Node.js精進
- 1、模塊化
- 2、異步編程
- 3、流
- 4、事件觸發器
- 5、HTTP
- 6、文件
- 7、日志
- 8、錯誤處理
- 9、性能監控(上)
- 10、性能監控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 監控系統
- 1、SDK
- 2、存儲和分析
- 3、性能監控
- 4、內存泄漏
- 5、小程序
- 6、較長的白屏時間
- 7、頁面奔潰
- 8、shin-monitor源碼分析
- 前端性能精進
- 1、優化方法論之測量
- 2、優化方法論之分析
- 3、瀏覽器之圖像
- 4、瀏覽器之呈現
- 5、瀏覽器之JavaScript
- 6、網絡
- 7、構建
- 前端體驗優化
- 1、概述
- 2、基建
- 3、后端
- 4、數據
- 5、后臺
- Web優化
- 1、CSS優化
- 2、JavaScript優化
- 3、圖像和網絡
- 4、用戶體驗和工具
- 5、網站優化
- 6、優化閉環實踐
- 數據結構與算法
- 1、鏈表
- 2、棧、隊列、散列表和位運算
- 3、二叉樹
- 4、二分查找
- 5、回溯算法
- 6、貪心算法
- 7、分治算法
- 8、動態規劃
- 程序員之路
- 大學
- 2011年
- 2012年
- 2013年
- 2014年
- 項目反思
- 前端基礎學習分享
- 2015年
- 再一次項目反思
- 然并卵
- PC網站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端學習之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 2024年
- 日志
- 2020