泛型是什么
泛型允許我們在強類型語言中編寫代碼時使用一些以后才指定的類型,在實例化時作為參數指明這些類型在ts中,定義函數,接口或者類的時候,不預先定義好具體的類型,而是在使用時候才指定類型的一種特性。
function returnItem(param:number):number{
return param
}
function returnItem(param:string):string{
return param
}
有兩個函數,一個返回number,一個返回string,這種方式代碼重復度高,需要些兩遍,雖然可以使用any類型去替代,但這在項目中基本是不允許的,這時候加上泛型
function returnItem<T>(param:T):T{
return param
}
泛型創造靈活,可復用代碼
使用方式
泛型通過<>
的形式進行表述,聲明:
- 函數
- 接口
- 類
函數聲明
function returnItem<T>(param:T):T{
return param
}
//定義泛型的時候,可以一次性定義多個類型參數,比如同時定義泛型T和U:
function swap<T,U>(tuple:[T,U]:[U,T]){
return [tuple[1],tuple[0]];
}
swap([7,'seven']);//['seven',7]
接口聲明
interface ReturnItemFn<T>{
(param:T):T
}
const returnItem:ReturnItemFn<number> = param => param
類聲明
使用泛型聲明類的時候,可以作用于類本身,也可以作用于類的成員函數
class Stack<T>{
private arr:T[] = []
public push(item:T){
this.arr.push(item);
}
public pop(){
this.arr.pop()
}
}
const stack = new Stack<number>();
如果上面只能傳遞string和number類型,這時候就可以使用<T extends xx>
的方式實現約束泛型
type Params = string | number
class Stack<T extends Params>{
private arr:T[] = []
public push(item:T){
this.arr.push(item)
}
public pop(){
this.arr.pop()
}
}
const stack = new Stack<boolean>() //類型“boolean”不滿足約束“Params”
除了上述的形式,泛型更高級的使用如下:
例如要設計一個函數,這個函數接受兩個參數,一個參數為對象,另一個參數為對象上的屬性,我們通過這兩個參數返回這個屬性的值
這時候就設計到泛型的索引類型和約束類型共同實現
索引類型、約束類型
索引類型 keyof T
把傳入的對象的屬性類型取出生成一個聯合類型,這里的泛型U被約束在這個聯合類型中
function getValue<T extends object, U extends keyof T>(obj:T,key:U){
return obj[key]
}
多類型約束
例如需要實現兩個接口的類型約束:
interface FirstInterface {
doSomething():number
}
interface SecondInterface {
doSomethingElse():string
}
可以創建一個接口繼承上述兩個接口
interface ChildInterface extends FirstInterface,SecondInterface {
}
class Demo<T extends ChildInterface>{
private genericProperty:T
constructor(genericProperty:T){
this.genericProperty = genericProperty
}
useT(){
this.genericProperty.doSomething()
this.genericProperty.doSomethingElse()
}
}