泛型
軟件工程中,我們不僅要?jiǎng)?chuàng)建一致的定義良好的API,同時(shí)也要考慮可重用性。 組件不僅能夠支持當(dāng)前的數(shù)據(jù)類型库说,同時(shí)也能支持未來的數(shù)據(jù)類型,這在創(chuàng)建大型系統(tǒng)時(shí)為你提供了十分靈活的功能片择。
在像C#和Java這樣的語言中潜的,可以使用泛型來創(chuàng)建可重用的組件,一個(gè)組件可以支持多種類型的數(shù)據(jù)字管。 這樣用戶就可以以自己的數(shù)據(jù)類型來使用組件啰挪。
創(chuàng)建第一個(gè)使用泛型的例子:identity函數(shù)信不。 這個(gè)函數(shù)會(huì)返回任何傳入它的值。 你可以把這個(gè)函數(shù)當(dāng)成是 echo命令亡呵。
不使用泛型:
function identity(arg: number): number {
return arg;
}
//或者使用any來定義函數(shù)
function identity(arg: any): any {
return arg;
}
雖然使用any類型后這個(gè)函數(shù)已經(jīng)能接收任何類型的arg參數(shù)抽活,但是卻丟失了一些信息:傳入的類型與返回的類型應(yīng)該是相同的。 如果我們傳入一個(gè)數(shù)字政己,我們只知道任何類型的值都有可能被返回。
因此掏愁,我們需要一種方法使返回值的類型與傳入?yún)?shù)的類型是相同的歇由。 這里,我們使用了 類型變量果港,它是一種特殊的變量沦泌,只用于表示類型而不是值。
function identity<T>(arg: T): T {
return arg;
}
我們給identity添加了類型變量T辛掠。 T幫助我們捕獲用戶傳入的類型(比如:number)谢谦,之后我們就可以使用這個(gè)類型。 之后我們?cè)俅问褂昧?T當(dāng)做返回值類型÷荞茫現(xiàn)在我們可以知道參數(shù)類型與返回值類型是相同的了回挽。 這允許我們跟蹤函數(shù)里使用的類型的信息。
我們把這個(gè)版本的identity函數(shù)叫做泛型猩谊,因?yàn)樗梢赃m用于多個(gè)類型千劈。 不同于使用 any,它不會(huì)丟
我們定義了泛型函數(shù)后牌捷,可以用兩種方法使用墙牌。失信息,像第一個(gè)例子那像保持準(zhǔn)確性暗甥,傳入數(shù)值類型并返回?cái)?shù)值類型喜滨。
let output = identity<string>("myString"); // type of output will be 'string'
這里我們明確的指定了T是string類型,并做為一個(gè)參數(shù)傳給函數(shù)撤防,使用了<>括起來而不是()虽风。
第二種方法更普遍。利用了類型推論 -- 即編譯器會(huì)根據(jù)傳入的參數(shù)自動(dòng)地幫助我們確定T的類型:
let output = identity("myString"); // type of output will be 'string'
注意我們沒必要使用尖括號(hào)(<>)來明確地傳入類型寄月;編譯器可以查看myString的值焰情,然后把T設(shè)置為它的類型。 類型推論幫助我們保持代碼精簡(jiǎn)和高可讀性剥懒。如果編譯器不能夠自動(dòng)地推斷出類型的話内舟,只能像上面那樣明確的傳入T的類型,在一些復(fù)雜的情況下初橘,這是可能出現(xiàn)的验游。
泛型類型
泛型函數(shù)的類型與非泛型函數(shù)的類型沒什么不同充岛,只是有一個(gè)類型參數(shù)在最前面,像函數(shù)聲明一樣:
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: <T>(arg: T) => T = 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; };