泛型是指在定義函數(shù),接口或類的時(shí)候梗肝,不先預(yù)先指定具體的類型,而使用的時(shí)候再指定類型的一種特性铺董。
簡(jiǎn)單的??
實(shí)現(xiàn)一個(gè)函數(shù)createArray巫击,它可以創(chuàng)建一個(gè)指定長(zhǎng)度的數(shù)組,同時(shí)將每一項(xiàng)都填充一個(gè)默認(rèn)值精续。
function createArray(length: number, value: any): Array<any>{
let result = [];
for (let i = 0; i < length; i++){
result[i] = value;
}
return result;
}
createArray(3, 'x');//['x','x','x']
Array<any>允許數(shù)組的每一項(xiàng)都為任意類型坝锰,但是我們預(yù)期的是,數(shù)組中每一項(xiàng)都應(yīng)該是輸入value
的類型重付。
這個(gè)時(shí)候就可以使用泛型了:
function createArray<T>(lenght: number, value: T): Array<T>{
let result: T[] = [];
for (let i = 0; i < lenght; i++){
result[i] = value;
}
return result;
}
console.log(createArray<string>(3, 'x'));
我們?cè)诤瘮?shù)名后添加了 <T>顷级,其中 T 用來(lái)指代任意輸入的類型,在后面的輸入 value: T 和輸出 Array<T> 中即可使用了堪夭。
在調(diào)用的時(shí)候愕把,可以指定它的類型為string,也可以不手動(dòng)指定森爽,讓類型推論自動(dòng)推算:
function createArray<T>(lenght: number, value: T):Array<T>{
let result: T[] = [];
for (let i = 0; i < length; i++){
result[i] = value;
}
return result;
}
console.log(createArray(3, 'x'));
多個(gè)類型參數(shù)
定義泛型的時(shí)候恨豁,可以一次定義多個(gè)類型參數(shù):
function swap<T, U>(tuple: [T, U]): [U, T]{
return [tuple[1], tuple[0]];
}
console.log(swap([1,'one']))
泛型約束
在函數(shù)內(nèi)部使用泛型變量的時(shí)候,由于事先不知道它是哪種類型爬迟,所以不能隨意的操作它的屬性或方法橘蜜。
function loggingIdentity<T>(arg: T): T {
console.log(arg.length);
return arg;// Property 'length' does not exist on type 'T'.
}
這時(shí)我們可以對(duì)泛型進(jìn)行約束,只允許這個(gè)函數(shù)傳入的那些包含length
屬性的變量付呕,這就是泛型約束:
interface lengthwise{
length: number;
}
function loggingIdentity<T extends lengthwise>(arg: T) {
console.log(arg.length);
return arg;
}
我們使用extens
約束了泛型 T
必須符合接口 lengthwise 的形狀计福,也就是必須包含length
屬性
多個(gè)類型參數(shù)之間互相約束
function copyFields<T extends U, U>(target: T, source: U): T{
for (let id in source){
target[id] = (<T>source)[id];
}
return target;
}
let x = { a: 1, b: 2, c: 3, d: 4 }
console.log(copyFields(x,{c:10,d:20}))
使用了兩個(gè)類型參數(shù),其中要求 T 繼承 U徽职,這樣就保證了 U 上不會(huì)出現(xiàn) T 中不存在的字段象颖。
泛型接口
使用接口的方式來(lái)定義一個(gè)函數(shù)需要符合的形狀:
interface SearchFunc{
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function (source: string, subString: string): boolean{
return source.search(subString) !== -1;
}
使用含有泛型的接口定義函數(shù)的形狀:
interface CreateArrayFunc {
<T>(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc;
createArray = function <T>(length: number, value: T): Array<T>{
let result:T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
把泛型參數(shù)提到接口名上:
interface CreateArrayFunc<T> {
(length: number, value: T): Array<T>;
}
let createArray: CreateArrayFunc<any>;
createArray = function<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
//使用泛型接口的時(shí)候,需要定義泛型的類型
泛型類
與泛型接口類似姆钉,泛型也可以用于類的類型定義中:
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; };
泛型參數(shù)的默認(rèn)類型
TypeScript 2.3 以后说订,我們可以為泛型中的類型參數(shù)指定默認(rèn)類型。當(dāng)使用泛型時(shí)沒有在代碼中直接指定類型參數(shù)潮瓶,從實(shí)際值參數(shù)中也無(wú)法推測(cè)出時(shí)陶冷,這個(gè)默認(rèn)類型就會(huì)起作用
function createArray<T = string>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}