要建立一個可重用的組件,其中的數據類型就必需要兼容不少的類型,那麼如何兼容呢,TypeScript提供了一個很好的方法:泛型數組
要兼容多種數據格式,可能會有人想到any,即ide
function identify(arg: any): any{ return arg; }
使用any存在一個問題,有可能傳入的值和返回的值不是同一種值,例如,傳入數字,可是不肯定返回的是什麼值函數
要解決這個問題,咱們須要引入類型變量-一種特殊的變量,只用於表示類型不表示值url
function identity<T>(arg: T): T { return arg; }
給identify添加了類型變量T,用來捕獲傳入值的類型,而後將返回值的類型也設置爲T,就實現了傳入值和返回值爲同一類型值的需求spa
咱們把identify這個函數叫作泛型,由於它適用於全部類型,而且不會有any類型存在的問題code
使用泛型的方法有兩種:blog
一、傳入全部的參數,包括類型參數接口
let output = identify<string>('qwe');
二、利用類型推論--即編譯器會根據傳入的參數自動地幫助咱們肯定T的類型ip
let output = identify('qwe');
在泛型中,咱們要合理正確的使用泛型變量T,要牢記T表示任何類型ci
錯誤使用:
function identify<T>(arg: T): T { console.log(arg.length);// Error: T doesn't have .length return arg; }
在泛型中咱們使用了length這個屬性,可是T表明任何類型,因此有多是number,而number是沒有length屬性的,因此會報錯
若是想要使用length這個屬性,咱們能夠建立數組
function identify<T>(arg: T[]): T[] { console.log(arg.length);// Error: T doesn't have .length return arg; }
泛型函數的類型與非泛型函數的類型沒什麼不一樣,只是有一個類型參數在最前面,像函數聲明同樣:
function identify<T>(arg: T): T { return arg; } let myIdentify: <U>(arg: U) => U = identify;
從上面的代碼中能夠看出也可使用不一樣的泛型參數名,只要在數量上和使用方式上能對應上就能夠
固然也能夠把泛型參數當作一個接口的參數,這樣就能夠知道這個接口具體用的是那種類型
interface GenericIdnetify<T>{ (arg: T): T; } function identity<T>(arg: T): T{ return arg; } let myGenericidentify: GenericIdnetify<string> = identity;
泛型類看上去與泛型接口差很少。 泛型類使用( <>
)括起泛型類型,跟在類名後面。
class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function(x, y) { return x + y; };
在前面的泛型變量中遇到了一個問題,就是在泛型中調用參數的length時,若是參數沒有Length屬性會報錯,而使用泛型約束,就是隻有知足必定的條件纔可使用這個泛型
爲此,咱們定義一個接口來描述約束條件。 建立一個包含 .length
屬性的接口,使用這個接口和extends
關鍵字還實現約束:
interface lengthwise{ length: number; } function identity<T extends lengthwise>(arg: T): T{ console.log(arg.length); return arg; } identity(123); //error identity('qwe'); //true
當傳入123時,沒有length屬性,就報錯,而傳入字符串qwe時則徹底正確
參考資料: