TS學習隨筆(五)->函數


這篇文章我們來看一下TS里面的函數

函數聲明

  在 JavaScript 中,有兩種常見的定義函數的方式——函數聲明(Function Declaration)和函數表達式(Function Expression):

// 函數聲明(Function Declaration)
function sum(x, y) {
    return x + y;
}

// 函數表達式(Function Expression)
let mySum = function (x, y) {
    return x + y;
};

一個函數有輸入和輸出,要在 TypeScript 中對其進行約束,需要把輸入和輸出都考慮到,其中函數聲明的類型定義較簡單:

function sum(x:number,y:number):number{
       return x+y  
}

注意,輸入多余的或者少於要求的參數,是不被允許的

sum(1, 2, 3);

// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.
sum(1);

// index.ts(4,1): error TS2346: Supplied parameters do not match any signature of call target.

 

函數表達式

  如果要我們現在寫一個對函數表達式(Function Expression)的定義,可能會寫成這樣

let mySun = function(x:number,y:number):number{
      return x + y  
}

 

這是可以通過編譯的,不過事實上,上面的代碼只對等號右側的匿名函數進行了類型定義,而等號左邊的 mySum,是通過賦值操作進行類型推論而推斷出來的。如果需要我們手動給 mySum 添加類型,則應該是這樣:

let mySum(x:number,y:number)=>number = function(x:number,y:number):number{
  return x+y}

注意不要混淆了 TypeScript 中的 => 和 ES6 中的 =>

在 TypeScript 的類型定義中,=> 用來表示函數的定義,左邊是輸入類型,需要用括號括起來,右邊是輸出類型。

在 ES6 中,=> 叫做箭頭函數,應用十分廣泛,

 

 

用接口定義函數的形狀

我們也可以使用接口的方式來定義一個函數需要符合的形狀:

interface SearchFunc{
       (source:string,subString:string):boolean
}    

let mySearch:SearchFunc;
mySearch = function(source: string,subString:string){
     return source.search(subString) !== -1  
}

可選參數

前面提到,輸入多余的(或者少於要求的)參數,是不允許的。那么如何定義可選的參數呢?

與接口中的可選屬性類似,我們用 ? 表示可選的參數:

function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

注意:可選參數必須接在必需參數后面。換句話說,可選參數后面不允許再出現必須參數了

function buildName(firstName?: string, lastName: string) {
    if (firstName) {
        return firstName + ' ' + lastName;
    } else {
        return lastName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName(undefined, 'Tom');

// index.ts(1,40): error TS1016: A required parameter cannot follow an optional parameter.

參數默認值

在 ES6 中,我們允許給函數的參數添加默認值,TypeScript 會將添加了默認值的參數識別為可選參數:

function buildName(firstName:string,lastName:string='Cat'){
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');

此時就不受「可選參數必須接在必需參數后面」的限制了:

function buildName(firstName: string = 'Tom', lastName: string) {
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let cat = buildName(undefined, 'Cat');

剩余參數

  ES6 中,可以使用 ...rest 的方式獲取函數中的剩余參數(rest 參數):

function push(array,...items){
     items.forEach(function(item){
        array.push(item)
  })  
}

let a = [];
push(a,1,2,3)

事實上,items 是一個數組。所以我們可以用數組的類型來定義它:

function push(array:any[],...items:any[]){
     items.forEach(function(item){
         array.push(item);
    })  
}

let a = []
push(a,1,2,3)

注意:rest 參數只能是最后一個參數

重載:

重載允許一個函數接受不同數量或類型的參數時,作出不同的處理。

 比如,我們需要實現一個函數 reverse,輸入數字 123 的時候,輸出反轉的數字 321,輸入字符串 'hello' 的時候,輸出反轉的字符串 'olleh'

利用聯合類型,我們可以這么實現:

function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

然而這樣有一個缺點,就是不能夠精確的表達,輸入為數字的時候,輸出也應該為數字,輸入為字符串的時候,輸出也應該為字符串。

這時,我們可以使用重載定義多個 reverse 的函數類型:

function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
    if (typeof x === 'number') {
        return Number(x.toString().split('').reverse().join(''));
    } else if (typeof x === 'string') {
        return x.split('').reverse().join('');
    }
}

上例中,我們重復定義了多次函數 reverse,前幾次都是函數定義,最后一次是函數實現。在編輯器的代碼提示中,可以正確的看到前兩個提示。

注意:TypeScript 會優先從最前面的函數定義開始匹配,所以多個函數定義如果有包含關系,需要優先把精確的定義寫在前面。

原文鏈接:https://github.com/xcatliu/typescript-tutorial/blob/master/basics/type-of-function.md


免責聲明!

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



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