成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

詳解 TypeScript 函數(shù)聲明和重載

開(kāi)發(fā) 前端
在 JavaScript 中,函數(shù)是構(gòu)建應(yīng)用的一塊基石,我們可以使用函數(shù)抽離可復(fù)用的邏輯、抽象模型、封裝過(guò)程。在TypeScript中,函數(shù)仍然是最基本、最重要的概念之一。下面就來(lái)看看TypeScript中的函數(shù)類型是如何定義和使用的。

在 JavaScript 中,函數(shù)是構(gòu)建應(yīng)用的一塊基石,我們可以使用函數(shù)抽離可復(fù)用的邏輯、抽象模型、封裝過(guò)程。在TypeScript中,函數(shù)仍然是最基本、最重要的概念之一。下面就來(lái)看看TypeScript中的函數(shù)類型是如何定義和使用的。

一、函數(shù)類型定義

1. 直接定義

函數(shù)類型的定義包括對(duì)參數(shù)和返回值的類型定義:

  1. function add(arg1: number, arg2: number): number { 
  2.   return x + y; 
  3. const add = (arg1: number, arg2: number): number => { 
  4.   return x + y; 
  5. }; 

這里用function字面量和箭頭函數(shù)兩種形式定義了add函數(shù)。函數(shù)參數(shù) arg1 和 arg2 都是數(shù)值類型,最后通過(guò)相加得到的結(jié)果也是數(shù)值類型。

如果在這里省略參數(shù)的類型,TypeScript 會(huì)默認(rèn)這個(gè)參數(shù)是 any 類型;如果省略返回值的類型,如果函數(shù)無(wú)返回值,那么 TypeScript 會(huì)默認(rèn)函數(shù)返回值是 void 類型;如果函數(shù)有返回值,那么 TypeScript 會(huì)根據(jù)定義的邏輯推斷出返回類型。

需要注意,在TypeScript中,如果函數(shù)沒(méi)有返回值,并且我們顯式的定義了這個(gè)函數(shù)的返回值類型為 undefined,那就會(huì)報(bào)錯(cuò):A function whose declared type is neither 'void' nor 'any' must return a value。正確的做法就是上面說(shuō)的,將函數(shù)的返回值類型聲明為void:

  1. function fn(x: number): void { 
  2.  console.log(x) 

一個(gè)函數(shù)的定義包括函數(shù)名、參數(shù)、邏輯和返回值。為函數(shù)定義類型時(shí),完整的定義應(yīng)該包括參數(shù)類型和返回值類型。上面都是在定義函數(shù)的指定參數(shù)類型和返回值類型。下面來(lái)定義一個(gè)完整的函數(shù)類型,以及用這個(gè)函數(shù)類型來(lái)規(guī)定一個(gè)函數(shù)定義時(shí)參數(shù)和返回值需要符合的類型。

  1. let add: (x: number, y: number) => number; 
  2. add = (arg1: number, arg2: number): number => arg1 + arg2; 
  3. add = (arg1: string, arg2: string): string => arg1 + arg2; // error 

這里定義了一個(gè)變量 add,給它指定了函數(shù)類型,也就是(x: number, y: number) => number,這個(gè)函數(shù)類型包含參數(shù)和返回值的類型。然后給 add 賦了一個(gè)實(shí)際的函數(shù),這個(gè)函數(shù)參數(shù)類型和返回類型都和函數(shù)類型中定義的一致,所以可以賦值。后面又給它賦了一個(gè)新函數(shù),而這個(gè)函數(shù)的參數(shù)類型和返回值類型都是 string 類型,這時(shí)就會(huì)報(bào)如下錯(cuò)誤:

  1. 不能將類型"(arg1: string, arg2: string) => string"分配給類型"(x: number, y: number) => number"。 
  2. 參數(shù)"arg1""x" 的類型不兼容。 
  3. 不能將類型"number"分配給類型"string"。 

注意: 函數(shù)中如果使用了函數(shù)體之外定義的變量,這個(gè)變量的類型是不體現(xiàn)在函數(shù)類型定義的。

2. 接口定義

使用接口可以清晰地定義函數(shù)類型。下面來(lái)使用接口為add函數(shù)定義函數(shù)類型:

  1. interface Add { 
  2.   (x: number, y: number): number; 
  3. let addAdd = (arg1: string, arg2: string): string => arg1 + arg2;  
  4. // error 不能將類型“(arg1: string, arg2: string) => string”分配給類型“Add” 

通過(guò)接口形式定義了函數(shù)類型,這個(gè)接口Add定義了這個(gè)結(jié)構(gòu)是一個(gè)函數(shù),兩個(gè)參數(shù)類型都是number類型,返回值也是number類型。當(dāng)指定變量add類型為Add時(shí),再要給add賦值,就必須是一個(gè)函數(shù),且參數(shù)類型和返回值類型都要滿足接口Add,顯然這個(gè)函數(shù)并不滿足條件,所以報(bào)錯(cuò)了。

3. 類型別名定義

可以使用類型別名來(lái)定義函數(shù)類型,這種形式更加直觀易讀:

  1. type Add = (x: number, y: number) => number; 
  2. let addAdd = (arg1: string, arg2: string): string => arg1 + arg2;  
  3. // error 不能將類型“(arg1: string, arg2: string) => string”分配給類型“Add” 

使用type關(guān)鍵字可以給任何定義的類型起一個(gè)別名。上面定義了 Add 這個(gè)別名后,Add就成為了一個(gè)和(x: number, y: number) => number一致的類型定義。上面定義了Add類型,指定add類型為Add,但是給add賦的值并不滿足Add類型要求,所以報(bào)錯(cuò)了。

注意,這里的=>與 ES6 中箭頭函數(shù)的=>不同。TypeScript 函數(shù)類型中的=>用來(lái)表示函數(shù)的定義,其左側(cè)是函數(shù)的參數(shù)類型,右側(cè)是函數(shù)的返回值類型;而 ES6 中的=>是函數(shù)的實(shí)現(xiàn)。

二、函數(shù)參數(shù)定義

1. 可選參數(shù)

TypeScript 會(huì)在編寫代碼時(shí)就檢查出調(diào)用函數(shù)時(shí)參數(shù)中存在的一些錯(cuò)誤:

  1. type Add = (x: number, y: number) => number; 
  2. let addAdd = (arg1, arg2) => arg1 + arg2; 
  3. add(1, 2);    // success 
  4. add(1, 2, 3); // error 應(yīng)有 2 個(gè)參數(shù),但獲得 3 個(gè) 
  5. add(1);       // error 應(yīng)有 2 個(gè)參數(shù),但獲得 1 個(gè) 

在JavaScript中,上面代碼中后面兩個(gè)函數(shù)調(diào)用都不會(huì)報(bào)錯(cuò), 只不過(guò)add(1, 2, 3)可以返回正確結(jié)果3,add(1)會(huì)返回NaN。而在TypeScript中我們?cè)O(shè)置了指定的參數(shù),那么在使用該類型時(shí),傳入的參數(shù)必須與定義的參數(shù)類型和數(shù)量一致。

但有時(shí)候,函數(shù)有些參數(shù)不是必須的,我們就可以將函數(shù)的參數(shù)設(shè)置為可選參數(shù)。可選參數(shù)只需在參數(shù)名后跟隨一個(gè)?即可:

  1. type Add = (x: number, y: number, z?: number) => number; 
  2. let addAdd = (arg1, arg2, arg3) => arg1 + arg2 + arg3; 
  3. add(1, 2);    // success   3 
  4. add(1, 2, 3); // success   6 

上面的代碼中,z是一個(gè)可選參數(shù),那他的類型就是number | undefined,表示參數(shù) z 就是可缺省的,那是不是意味著可缺省和類型是 undefined 等價(jià)呢?來(lái)看下面的例子:

  1. function log(x?: number) { 
  2.   console.log(x); 
  3. function log1(x: number | undefined) { 
  4.   console.log(x); 
  5. log(); 
  6. log(undefined); 
  7. log1();    // Expected 1 arguments, but got 0 
  8. log1(undefined); 

可以看到,第三次函數(shù)調(diào)用報(bào)錯(cuò)了,這里的 ?: 表示在調(diào)用函數(shù)時(shí)可以不顯式的傳入?yún)?shù)。但是,如果聲明了參數(shù)類型為 number | undefined,就表示函數(shù)參數(shù)是不可缺省且類型必須是 number 或者 undfined。

需要注意,可選參數(shù)必須放在必選參數(shù)后面,這和在 JS 中定義函數(shù)是一致的。來(lái)看例子:

  1. type Add = (x?: number, y: number) => number;  // error 必選參數(shù)不能位于可選參數(shù)后。 

在TypeScript中,可選參數(shù)必須放到最后,上面把可選參數(shù)x放到了必選參數(shù)y前面,所以報(bào)錯(cuò)了。在 JavaScript 中是沒(méi)有可選參數(shù)這個(gè)概念的,只不過(guò)在編寫邏輯時(shí),可能會(huì)判斷某個(gè)參數(shù)是否為undefined,如果是則說(shuō)明調(diào)用該函數(shù)的時(shí)候沒(méi)有傳這個(gè)參數(shù),要做下兼容處理;而如果幾個(gè)參數(shù)中,前面的參數(shù)是可不傳的,后面的參數(shù)是需要傳的,就需要在該可不傳的參數(shù)位置傳入一個(gè) undefined 占位才行。

2. 默認(rèn)參數(shù)

在 ES6 標(biāo)準(zhǔn)出來(lái)之前,默認(rèn)參數(shù)實(shí)現(xiàn)起來(lái)比較繁瑣:

  1. var count = 0; 
  2. function counter(step) { 
  3.   step = step || 1; 
  4.   count += step; 

上面定義了一個(gè)計(jì)數(shù)器增值函數(shù),這個(gè)函數(shù)有一個(gè)參數(shù) step,即每次增加的步長(zhǎng),如果不傳入?yún)?shù),那么 step 接受到的就是 undefined,undefined 轉(zhuǎn)換為布爾值是 false,所以 step || 1 這里取了 1,從而達(dá)到了不傳參數(shù)默認(rèn) step === 1 的效果。

在 ES6 中,定義函數(shù)時(shí)給參數(shù)設(shè)默認(rèn)值直接在參數(shù)后面使用等號(hào)連接默認(rèn)值即可:

  1. const count = 0; 
  2. const counter = (step = 1) => { 
  3.   count += step; 
  4. }; 

當(dāng)為參數(shù)指定了默認(rèn)參數(shù)時(shí),TypeScript 會(huì)識(shí)別默認(rèn)參數(shù)的類型;當(dāng)調(diào)用函數(shù)時(shí),如果給這個(gè)帶默認(rèn)值的參數(shù)傳了別的類型的參數(shù)則會(huì)報(bào)錯(cuò):

  1. const add = (x: number, y = 2) => { 
  2.   return x + y; 
  3. }; 
  4. add(1, "ts"); // error 類型"string"的參數(shù)不能賦給類型"number"的參數(shù) 

當(dāng)然也可以顯式地給默認(rèn)參數(shù) y 設(shè)置類型:

  1. const add = (x: number, y: number = 2) => { 
  2.   return x + y; 
  3. }; 

注意:函數(shù)的默認(rèn)參數(shù)類型必須是參數(shù)類型的子類型,如下代碼:

  1. const add = (x: number, y: number | string = 2) => { 
  2.   return x + y; 
  3. }; 

這里 add 函數(shù)參數(shù) y 的類型為可選的聯(lián)合類型 number | string,但是因?yàn)槟J(rèn)參數(shù)數(shù)字類型是聯(lián)合類型 number | string 的子類型,所以 TypeScript 也會(huì)檢查通過(guò)。

3. 剩余參數(shù)

在 JavaScript 中,如果定義一個(gè)函數(shù),這個(gè)函數(shù)可以輸入任意個(gè)數(shù)的參數(shù),那么就無(wú)法在定義參數(shù)列表的時(shí)候挨個(gè)定義。在 ES6 發(fā)布之前,需要用 arguments 來(lái)獲取參數(shù)列表。arguments 是一個(gè)類數(shù)組對(duì)象,它包含在函數(shù)調(diào)用時(shí)傳入函數(shù)的所有實(shí)際參數(shù),它還包含一個(gè) length 屬性,表示參數(shù)個(gè)數(shù)。下面來(lái)模擬實(shí)現(xiàn)函數(shù)的重載:

  1. function handleData() { 
  2.   if (arguments.length === 1) return arguments[0] * 2; 
  3.   else if (arguments.length === 2) return arguments[0] * arguments[1]; 
  4.   else return Array.prototype.slice.apply(arguments).join("_"); 
  5. handleData(2); // 4 
  6. handleData(2, 3); // 6 
  7. handleData(1, 2, 3, 4, 5); // '1_2_3_4_5' 

這段代碼如果在TypeScript環(huán)境中執(zhí)行,三次handleData的調(diào)用都會(huì)報(bào)錯(cuò),因?yàn)閔andleData函數(shù)定義的時(shí)候沒(méi)有參數(shù)。

在 ES6 中,加入了…拓展運(yùn)算符,它可以將一個(gè)函數(shù)或?qū)ο筮M(jìn)行拆解。它還支持用在函數(shù)的參數(shù)列表中,用來(lái)處理任意數(shù)量的參數(shù):

  1. const handleData = (arg1, ...args) => { 
  2.   console.log(args); 
  3. }; 
  4. handleData(1, 2, 3, 4, 5); // [ 2, 3, 4, 5 ] 

在 TypeScript 中可以為剩余參數(shù)指定類型:

  1. const handleData = (arg1: number, ...args: number[]) => { 
  2.  
  3. }; 
  4. handleData(1, "a"); // error 類型"string"的參數(shù)不能賦給類型"number"的參數(shù) 

三、函數(shù)重載

在多數(shù)的函數(shù)中,是只能接受一組固定的參數(shù)。但是一些函數(shù)可以接收可變數(shù)量的參數(shù)、不同類型的參數(shù),甚至可以根據(jù)調(diào)用函數(shù)的方式來(lái)返回不同類型的參數(shù)。要使用此類函數(shù),TypeScript我們提供了函數(shù)重載功能。下面來(lái)看看函數(shù)重載是如何工作的。

1. 函數(shù)簽名

先來(lái)看一個(gè)簡(jiǎn)單的例子:

  1. function greet(person: string): string { 
  2.   return `Hello, ${person}!`; 
  3.  
  4. greet('World'); // 'Hello, World!' 

這里的greet方法接收一個(gè)參數(shù)name,類型為string。那如果想讓greet方法來(lái)接收一組名稱怎么辦?那這時(shí)greet函數(shù)會(huì)接收字符串或字符串?dāng)?shù)組作為參數(shù),并返回字符串或字符串?dāng)?shù)組。那該如何改造這個(gè)函數(shù)?主要有兩種方式:通過(guò)判斷參數(shù)類型來(lái)修改函數(shù)簽名

  1. function greet(person: string | string[]): string | string[] { 
  2.   if (typeof person === 'string') { 
  3.     return `Hello, ${person}!`; 
  4.   } else if (Array.isArray(person)) { 
  5.     return person.map(name => `Hello, ${name}!`); 
  6.   } 
  7.   throw new Error('error'); 
  8.  
  9. greet('World');          // 'Hello, World!' 
  10. greet(['TS''JS']);     // ['Hello, TS!''Hello, JS!'

這是最簡(jiǎn)單直接的方式,但是在某些情況下,我們希望單獨(dú)定義調(diào)用函數(shù)的方式,這時(shí)就可以使用函數(shù)重載。

2. 函數(shù)重載

當(dāng)修改函數(shù)簽名的方式比較復(fù)雜或者涉及到多種數(shù)據(jù)類型時(shí),建議使用函數(shù)重載來(lái)完成。在函數(shù)重載中,我們需要定義重載簽名和實(shí)現(xiàn)簽名。重載函數(shù)簽名只定義函數(shù)的參數(shù)和返回值類型,并不會(huì)定義函數(shù)的正文。對(duì)于一個(gè)函數(shù)不同的調(diào)用方式,就可以有多個(gè)重載簽名。

下面來(lái)實(shí)現(xiàn)greet()函數(shù)的重載:

  1. // 重載簽名 
  2. function greet(person: string): string; 
  3. function greet(persons: string[]): string[]; 
  4.   
  5. // 實(shí)現(xiàn)簽名 
  6. function greet(person: unknown): unknown { 
  7.   if (typeof person === 'string') { 
  8.     return `Hello, ${person}!`; 
  9.   } else if (Array.isArray(person)) { 
  10.     return person.map(name => `Hello, ${name}!`); 
  11.   } 
  12.   throw new Error('error'); 

這里greet()函數(shù)有兩個(gè)重載簽名和一個(gè)實(shí)現(xiàn)簽名。每個(gè)重載簽名都描述了調(diào)用函數(shù)的一種方式。我們可以使用字符串參數(shù)或使用字符串參數(shù)數(shù)組來(lái)調(diào)用greet()函數(shù)。

現(xiàn)在就可以使用字符串或字符串?dāng)?shù)組的參數(shù)調(diào)用greet()):

  1. greet('World');          // 'Hello, World!' 
  2. greet(['TS''JS']);     // ['Hello, TS!''Hello, JS!'

在定義函數(shù)重載時(shí),需要注意以下兩點(diǎn):

(1)函數(shù)簽名是可以調(diào)用的

雖然上面我們定義了重載簽名和簽名方法,但是簽名實(shí)現(xiàn)時(shí)不能直接調(diào)用的,只有重載簽名可以調(diào)用:

  1. const someValue: unknown = 'Unknown'
  2. greet(someValue); 

這樣調(diào)用的話就會(huì)報(bào)錯(cuò):

  1. No overload matches this call. 
  2. Overload 1 of 2, '(person: string): string', gave the following error. 
  3.  Argument of type 'unknown' is not assignable to parameter of type 'string'
  4. Overload 2 of 2, '(persons: string[]): string[]', gave the following error. 
  5.   Argument of type 'unknown' is not assignable to parameter of type 'string[]' 

也就是說(shuō),即使簽名實(shí)現(xiàn)接收unknown類型的參數(shù),但是我們不能直接給greet()方法來(lái)傳遞unknown類型的參數(shù),參數(shù)只能是函數(shù)重載簽名中定義的參數(shù)類型。

(2)實(shí)現(xiàn)簽名必須是通用的

在實(shí)現(xiàn)簽名時(shí),定義的數(shù)據(jù)類型需要是通用的,以包含重載簽名。假如我們把greet()方法的返回值類型定義為string,這時(shí)就會(huì)出問(wèn)題了:

  1. function greet(person: string): string; 
  2. function greet(persons: string[]): string[]; 
  3.  
  4. function greet(person: unknown): string { 
  5.   // ... 
  6.   throw new Error('error'); 

此時(shí)string[]類型就會(huì)和string不兼容。所以,實(shí)現(xiàn)簽名的返回類型和參數(shù)類型都要包含所有重載簽名中的參數(shù)類型和返回值類型,保證是通用的。

3. 方法重載

除了常規(guī)函數(shù)外,類中的方法也可以過(guò)載,比如用重載方法greet()來(lái)實(shí)現(xiàn)一個(gè)類:

  1. class Greeter { 
  2.   message: string; 
  3.   
  4.   constructor(message: string) { 
  5.     this.message = message; 
  6.   } 
  7.   
  8.   greet(person: string): string; 
  9.   greet(persons: string[]): string[]; 
  10.  
  11.   greet(person: unknown): unknown { 
  12.     if (typeof person === 'string') { 
  13.       return `${this.message}, ${person}!`; 
  14.     } else if (Array.isArray(person)) { 
  15.       return person.map(name => `${this.message}, ${name}!`); 
  16.     } 
  17.     throw new Error('error'); 
  18.   } 

Greeter類中包含了greet()重載方法:這里面有兩個(gè)描述如何調(diào)用方法的重載簽名,以及包含其實(shí)現(xiàn)簽名。這樣我們就可以通過(guò)兩種方式調(diào)用hi.greet():

  1. const hi = new Greeter('Hi'); 
  2.   
  3. hi.greet('World');          // 'Hello, World!' 
  4. hi.greet(['TS''JS']);     // ['Hello, TS!''Hello, JS!'

 

責(zé)任編輯:武曉燕 來(lái)源: 前端充電寶
相關(guān)推薦

2023-04-14 15:44:20

TypeScrip函數(shù)重載

2021-12-10 09:11:36

TypeScript 函數(shù)重載 TS 前端

2017-08-01 00:19:15

Javascript函數(shù)函數(shù)聲明

2009-11-16 16:59:03

PHP構(gòu)造函數(shù)

2022-02-28 08:17:24

重載函數(shù)JS前端

2016-10-11 13:32:50

函數(shù)式TypeScriptJavascript

2011-05-30 16:11:46

Javascript

2009-07-31 16:00:30

C#函數(shù)重載

2010-01-18 16:56:30

C++函數(shù)

2009-12-22 16:36:38

WCF重載

2016-12-26 09:23:18

C++函數(shù)覆蓋

2016-09-30 09:43:17

JavascriptTypeScript函數(shù)式編程

2024-04-15 12:54:40

2021-11-08 11:02:01

Go函數(shù)重載

2024-11-13 19:03:14

2021-06-28 08:01:57

JS 函數(shù)表達(dá)式函數(shù)聲明

2010-01-20 17:48:07

C++ 函數(shù)重載

2009-09-01 11:28:32

C#使用函數(shù)重載

2009-02-24 16:17:41

日期時(shí)間函數(shù)

2014-04-16 10:54:45

Javascript遞歸調(diào)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 国产精品久久久久久久久图文区 | 视频在线观看一区 | 成人3d动漫一区二区三区91 | 国产精品污www一区二区三区 | 99精品国产一区二区青青牛奶 | 雨宫琴音一区二区在线 | 亚洲精选一区 | 国产精品久久久久久久久久免费 | 欧美日韩看片 | 久久手机在线视频 | 在线视频成人 | 高清色视频 | 国产精品久久久久一区二区三区 | 视频1区2区 | 欧美不卡视频一区发布 | 理论片87福利理论电影 | 麻豆av在线| 欧美精品国产一区二区 | 日韩免费视频一区二区 | 成人精品免费视频 | 国产精品一区二区日韩 | 精品一区av | 国精品一区二区 | 日韩有码在线播放 | 亚洲国产成人在线视频 | 国产精品网址 | 欧美性视频在线播放 | 日韩在线播放一区 | 亚洲国产精品va在线看黑人 | 国产精品av久久久久久毛片 | 成人影| 国产精品久久久久久久久久免费看 | 二区亚洲| 欧美日本亚洲 | 天天摸天天干 | 亚洲精品美女 | 日韩久久久久久 | 国产成人一区二区三区电影 | 久久精品毛片 | a在线观看 | 日韩成人|