深入淺出TypeScript(3)- 函數重載和泛型


面向對象特性中,最根本的就是面向對象的三大基本特征:封裝、繼承、多態。同時,TypeScript中也存在多態的使用,比如函數重載,今天我們先看一下函數重載以及泛型的概念。

什么是函數重載

簡單來說,函數重載具有兩個特征:名稱相同,參數不同(參數類型、個數不同。)所以,函數重載的解釋應該是具備不同參數的同名函數。注意:函數重載是多態的一種體現

函數重載的聲明和實現

TypeScript中,函數重載主要包括兩部分:函數聲明,和函數實現。函數聲明主要是TSC解析的一種聲明體現,實際編譯中,並不會編譯成具體代碼。我們可以通過TypeScript的playground來查看。

1、參數不同的函數重載

加入我們有一個打印函數,可以打印輸入的一個string信息,我們可以將函數聲明如下:

// 函數聲明
function print(info: string): void;

  

而還有另一種情況,就是輸入的有可能是兩個string類型的參數,我們都需要打印下來,於是我們的函數聲明可以是這樣:

// 函數聲明
function print(info: string, message: string): void;

  

而當這兩種聲明,同時存在TypeScript的聲明文件中,我們就需要用函數重載來實現,這是JavaScript沒有的特性。

而實現函數重載的要求就是,我們要在一個更為寬泛的范圍去實現函數重載,所以,TypeScript中的我們實現print函數如下:

// 在更寬泛的范圍,我們用可選參數來實現重載
function print(info: string, message ?: string) {
    let printValue: string = info;
    if(message){
        printValue += message;
    }
    console.log(printValue);
}

  

2、參數個數相同,但類型不同的函數重載

函數重載的第二種情況,參數個數相同,但是參數類型不一樣,這種情況下也可以通過重載來實現。

比如,上述打印信息的函數,有可能接受的輸入是一個string字符串,也有可能輸入接受的是一個number類型的數字,那么我們第一步的函數聲明便是如下:

function print(info: string): void;
function print(num: number): void;

  

從上可以看到,我們的函數聲明中,參數的類型是不同的,在這種情況下,TypeScript是如何在一個寬泛的范圍內實現呢?這里就要用到聯合類型,如下所示:

function print(message: string | number) {
    console.log(message)
}

  

函數重載的總結

從我們實現兩個函數重載的例子可以看出,我們在TypeScript中實現函數重載的方式分別是利用了TypeScript中的兩個類型特性:可選類型以及聯合類型。

所以,如果從便捷的角度來講,我們如果是遇到了類似的實現,其實可以直接使用可選參數和聯合類型來實現自己想要的函數效果。

泛型

在函數重載的不同參數類型,相同參數個數的重載中,我們介紹了它的重載實現方式,利用聯合類型來實現,但是如果要打印出來的類型有很多,那么我們最終只能用any類型來實現print函數了。

但是,如果用any類型實現一個可以打印任意值的print函數,這樣又讓我們的函數變得類型缺失,這個時候,泛型這種解決方案也就應運而生。

什么是泛型

泛型指的是一種情況:定義是可以是任意類型,但是在編譯的時候,必須有明確的類型。

有點繞,那么我們用泛型來實現上述第二個函數重載的例子,結合這個例子,可以體會一下這句話的含義。

function print<T>(message: T) {
     console.log(message);
}

  

在這個函數中,泛型表示的方式是:函數名稱<泛型參數>(arg: 泛型參數)。

這個函數在聲明之后,函數類型是一個泛型。我們可以傳遞任意的類型參數到print函數中,但是當我們傳遞一個string類型的時候,這個函數便是一個string類型的函數了,已經在tsc編譯階段開始明確指定類型,這是和any函數所不一樣的地方。

泛型的好處

首先,我們不用定義過多的聯合類型來讓函數變得復雜而又冗長,如:

function print(arg: string | number | boolean | array | 自定義類型) {
    // 我們應該盡量避免多類型的傳值函數,此時我們應該用泛型來實現。
}

  

其次,泛型可以是任何類型,但是在編譯時一定是類型確定的。而且泛型也可以有繼承屬性,可以繼承接口獲取更多的類型定義等。

function print<T extends Interface> (arg: T) {
    // 通過繼承,來讓泛型有更多的可變性。
}

  

最后,類型別名也可以是泛型,如我們可以做如下類型定義:

type Person<T> = { age: T } 

  

泛型總結

總體來說,利用泛型,也是為了更准確的讓我們使用類型思維,是為了更准確的描述參數、或者聲明的類型准確性,如果能夠熟練的掌握泛型,那么在TypeScript的開發中,將會有不一樣的體驗。

而常常以類型思維去思考JavaScript中的函數或者變量,我們也就會減少很多因為類型方面的犯錯,使得我們的項目不僅更好的測試,也會更少的出錯。

不得不說,在大前端領域,類型思維的缺失的確是個普遍現象,如果將類型思維撿起來,將會是一個可能存在着痛苦的過程,但是我相信,如果你做到了,那么你不僅會在開發代碼的時候會更謹慎,能開發出更優秀的應用程序,還會體驗到前端行業別樣的魅力。

我的博客地址:http://www.gaoyunjiao.fun/?p=130


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM