很多時候我們希望一個函數或者一個類可以支持多種數據類型,有很大的靈活性。
很多小夥伴可能會想到函數重載,聯合類型,或者any類型等。
函數重載代碼量大,聯合類型冗長。
function log(value:any):any{
console.log(value);
return value;
}
雖然使用any類型可以滿足我們的需求,但是缺失類型信息,這不是我們所希望的,這裏我們就可以使用泛型。
泛型函數:
不預先確定的函數類型,具體的類型在使用的時候才能確定
// 泛型函數
function logs<T>(value:T):T{
console.log(value);
return value;
}
// 類型T不需要預先指定,相當於any類型 ;保證了輸入參數和返回值是一致的
泛型函數有兩種調用方式:
- 指明參數類型:logs<string[]>(['a','b']);
- 利用TS的類型推斷,省略參數類型:logs(['c','d'])
我們不僅可以用泛型來定義一個函數,也可以定義一個函數類型
type Log=<T>(value:T)=>T;
let MyLog:Log=log;
泛型約束接口
// 這裏僅僅使用泛型來約束了一個函數
interface L{
<T>(value:T):T
}
// 使用泛型來約束接口的其他成員,當泛型約束整個接口的時候,實現時我們必須指定一個類型
interface Lj<T>{j
(value:T):T
}
泛型可以理解爲代表函數類型的參數。
泛型類:
//泛型約束類成員
class Logs<T>{
run(value:T){
console.log(value);
return value;
}
}
let log1=new Logs<number>(); //顯示傳入T的類型
log1.run(1);
let log2=new Logs(); //當不指定類型參數的時候,value的值就可以是任意的類型
log2.run('lll')
// 泛型不能應用於類的靜態成員
class Logs<T>{
static run(value:T){ //報錯
console.log(value);
return value;
}
}
泛型約束
function Lg<T>(value:T):T{
console.log(value);
console.log(value,value.length); //T上沒有length屬性
return value;
}
interface Len{
length:number
}
function L<T extends Len>(value:T):T{
console.log(value);
console.log(value,value.length); //T上沒有length屬性,繼承了接口len的length屬性
return value;
}
L([1,2]); // 參數受到泛型的約束,必須具有length屬性
L(1); //類型“1”的參數不能賦給類型“Len”的參數。
泛型的好處:
-
函數和類可以輕鬆的支持多種類型,增強程序的擴展性
-
不必寫多條函數重載,冗長的聯合類型聲明,增強代碼的可讀性
-
靈活控制類型之間的約束