TypeScript中的範型

LeonVincent發表於2019-06-20

一、定義

比如我們有一個函式,如果不使用範型是這樣的

function getData(arg: number): number {
    return arg;
}
複製程式碼

它只能傳入number型別,如果我們要傳入一個string型別的是編譯不通過的,所以我們可以寫另一個函式或者用any型別

function getData1(arg: string): string {
    return arg;
}
function getData2(arg: any): any {
    return arg;
}
複製程式碼

那麼問題來了,如果重新寫那麼我們就不能做到複用了,如果用any就不能保證傳進去的型別和傳出來的型別統一,所以我們有了範型

function getData<T>(arg: T): T {
    return arg;
}
getData<number>(123)
getData<string>(123)
getData(false)//利用了型別推論,編譯器會根據傳入的引數自動地幫助我們確定T的型別
複製程式碼

T:表示範型,具體什麼型別是呼叫的這個方法的時候決定的(注意:T也可以是任意其他字母) 所以範型可以支援不確定的資料型別,傳入的引數和返回值的型別一致。

二、範型變數

如果我們想列印一個陣列的長度

function getLength<T>(arg: T): T {
    console.log(arg.length);  // Error: T doesn't have .length
    return arg;
}
複製程式碼

如果這麼做,編譯器會報錯說我們使用了arg的.length屬性,但是沒有地方指明arg具有這個屬性。 記住,這些型別變數代表的是任意型別,所以使用這個函式的人可能傳入的是個數字,而數字是沒有.length屬性的。
現在假設我們想操作T型別的陣列而不直接是T。由於我們操作的是陣列,所以.length屬性是應該存在的。 我們可以像建立其它陣列一樣建立這個陣列:

function getLength<T>(arg: T[]): T[] {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}
複製程式碼

三、範型類

泛型類使用(<>)括起泛型型別,跟在類名後面。

class Minclass<T> {
    public list: T[] = []
    add(value: T):void {
        this.list.push(value)
    }
    min():T{
        let minNum = this.list[0]
        for(let i =0; i < this.list.length; i++){
            if(minNum > this.list[i]){
                minNum = this.list[i]
            }
        }
        return minNum
    }
}
let m = new Minclass<number>()
m.add(2)
m.add(6)
m.min() //2
let s = new Minclass<string>()
s.add('m')
s.add('c')
s.min()//c
複製程式碼

四、範型介面

interface ConfigFn{
    <T>(value:T):T
}
let getData:ConfigFn = function<T>(value:T):T{
    return value
}
複製程式碼

通用範型介面:

function getData<T>(value:T):T{
    return value
}
interface ConfigFn<T>{
    (value:T):T
}
let getData:ConfigFn<string> = getData
let getData1:ConfigFn<number> = getData

複製程式碼

五、在泛型約束中使用型別引數

class User{
    username: string
    password: string
}
class Mysql{
    add (user:User):boolean{
        console.log(user)
        return true
    }
}
let u = new User()
u.username = '張三'
u.password = '123'
let m = new Mysql()
m.add(u)
複製程式碼

我們可以通過範型約束來更好的實現上面的程式碼

class Mysql<T>{
    add(info:T):boolean{
        console.log(Info)
        return true
    }
}
let u = new User()
u.username = '張三'
u.password = '123'
let my = new Mysql<User>()
my.add(u)
複製程式碼

相關文章