第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

TypeScript 泛型(Generic)

本節(jié)開始介紹 TypeScript 一些進階知識點,第一個要介紹的泛型是 TypeScript 中非常重要的一個概念,它是一種用以增強函數(shù)、類和接口能力的非常可靠的手段。

使用泛型,我們可以輕松地將那些輸入重復(fù)的代碼,構(gòu)建為可復(fù)用的組件,這給予了開發(fā)者創(chuàng)造靈活、可重用代碼的能力。

1. 慕課解釋

泛型在傳統(tǒng)的面向?qū)ο笳Z言中極為常見,可以使用泛型來創(chuàng)建可重用的組件,一個組件可以支持多種類型的數(shù)據(jù)。

通俗來講:泛型是指在定義函數(shù)、接口或者類時,未指定其參數(shù)類型,只有在運行時傳入才能確定。那么此時的參數(shù)類型就是一個變量,通常用大寫字母 T 來表示,當(dāng)然你也可以使用其他字符,如:U、K等。

語法:在函數(shù)名、接口名或者類名添加后綴 <T>

function generic<T>() {}
interface Generic<T> {}
class Generic<T> {}

2. 初識泛型

之所以使用泛型,是因為它幫助我們?yōu)椴煌愋偷妮斎?,?fù)用相同的代碼。

比如寫一個最簡單的函數(shù),這個函數(shù)會返回任何傳入它的值。如果傳入的是 number 類型:

function identity(arg: number): number {
    return arg
}

如果傳入的是 string 類型:

function identity(arg: string): string {
    return arg
}

通過泛型,可以把兩個函數(shù)統(tǒng)一起來:

function identity<T>(arg: T): T {
  return arg
}

需要注意的是,泛型函數(shù)的返回值類型是根據(jù)你的業(yè)務(wù)需求決定,并非一定要返回泛型類型 T:

function identity<T>(arg: T): string {
  return String(arg)
}

代碼解釋: 入?yún)⒌念愋褪俏粗?,但是通過 String 轉(zhuǎn)換,返回字符串類型。

3. 多個類型參數(shù)

泛型函數(shù)可以定義多個類型參數(shù):

function extend<T, U>(first: T, second: U): T & U {
  for(const key in second) {
    (first as T & U)[key] = second[key] as any
  }
  return first as T & U
}

代碼解釋: 這個函數(shù)用來合并兩個對象,具體實現(xiàn)暫且不去管它,這里只需要關(guān)注泛型多個類型參數(shù)的使用方式,其語法為通過逗號分隔 <T, U, K>。

4. 泛型參數(shù)默認(rèn)類型

函數(shù)參數(shù)可以定義默認(rèn)值,泛型參數(shù)同樣可以定義默認(rèn)類型:

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!
function min<T = number>(arr:T[]): T{
  let min = arr[0]
  arr.forEach((value)=>{
     if(value < min) {
         min = value
     }
  })
   return min
}
console.log(min([20, 6, 8n])) // 6
運行案例 點擊 "運行案例" 可查看在線運行效果

解釋: 同樣的不用去關(guān)注這個最小數(shù)函數(shù)的具體實現(xiàn),要知道默認(rèn)參數(shù)語法為 <T = 默認(rèn)類型>。

5. 泛型類型與泛型接口

先來回顧下之前章節(jié)介紹的函數(shù)類型:

const add: (x: number, y: number) => string = function(x: number, y: number): string {
  return (x + y).toString()
}

等號左側(cè)的 (x: number, y: number) => string 為函數(shù)類型。

再看下泛型類型:

function identity<T>(arg: T): T {
  return arg
}

let myIdentity: <T>(arg: T) => T = identity

同樣的等號左側(cè)的 <T>(arg: T) => T 即為泛型類型,它還有另一種帶有調(diào)用簽名的對象字面量書寫方式:{ <T>(arg: T): T }:

function identity<T>(arg: T): T {
  return arg
}

let myIdentity: { <T>(arg: T): T } = identity

這就引導(dǎo)我們?nèi)懙谝粋€泛型接口了。把上面例子里的對象字面量拿出來作為一個接口:

interface GenericIdentityFn {
  <T>(arg: T): T
}

function identity<T>(arg: T): T {
  return arg
}

let myIdentity: GenericIdentityFn = identity

進一步,把泛型參數(shù)當(dāng)作整個接口的一個參數(shù),我們可以把泛型參數(shù)提前到接口名上。這樣我們就能清楚的知道使用的具體是哪個泛型類型:

interface GenericIdentityFn<T> {
  (arg: T): T
}

function identity<T>(arg: T): T {
  return arg
}

let myIdentity: GenericIdentityFn<number> = identity

注意,在使用泛型接口時,需要傳入一個類型參數(shù)來指定泛型類型。示例中傳入了 number 類型,這就鎖定了之后代碼里使用的類型。

6. 泛型類

始終要記得,使用泛型是因為可以復(fù)用不同類型的代碼。下面用一個最小堆算法舉例說明泛型類的使用:

class MinClass {
  public list: number[] = []
  add(num: number) {
    this.list.push(num)
  }
  min(): number {
    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
  }
}

代碼解釋: 示例中我們實現(xiàn)了一個查找 number 類型的最小堆類,但我們的最小堆還需要支持字符串類型,此時就需要泛型的幫助了:

實例演示
預(yù)覽 復(fù)制
復(fù)制成功!
// 類名后加上 <T>
class MinClass<T> {
  public list: T[] = []
  add(num: T) {
    this.list.push(num)
  }
  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<string>()
m.add('hello')
m.add('world')
m.add('generic')
console.log(m.min()) // generic
運行案例 點擊 "運行案例" 可查看在線運行效果

代碼解釋:

第 2 行,在聲明 類 MinClass 的后面后加上了 <T>,這樣就聲明了泛型參數(shù) T,作為一個變量可以是字符串類型,也可以是數(shù)字類型。

7. 泛型約束

語法:通過 extends 關(guān)鍵字來實現(xiàn)泛型約束。

如果我們很明確傳入的泛型參數(shù)是什么類型,或者明確想要操作的某類型的值具有什么屬性,那么就需要對泛型進行約束。通過兩個例子來說明:

interface User {
  username: string
}

function info<T extends User>(user: T): string {
  return 'imooc ' + user.username
}

代碼解釋: 示例中,第 5 行,我們約束了入?yún)?user 必須包含 username 屬性,否則在編譯階段就會報錯。

下面再看另外一個例子:

type Args = number | string

class MinClass<T extends Args> {}

const m = new MinClass<boolean>() // Error, 必須是 number | string 類型

代碼解釋:

第 3 行,約束了泛型參數(shù) T 繼承自類型 Args,而類型 Args 是一個由 number 和 string 組成的聯(lián)合類型。

第 5 行,泛型參數(shù)只能是 number 和 string 中的一種,傳入 boolean 類型是錯誤的。

8. 多重類型泛型約束

通過 <T extends Interface1 & Interface2> 這種語法來實現(xiàn)多重類型的泛型約束:

interface Sentence {
  title: string,
  content: string
}

interface Music {
  url: string
}

class Classic<T extends Sentence & Music> {
  private prop: T

  constructor(arg: T) {
    this.prop = arg
  }

  info() {
    return {
      url: this.prop.url,
      title: this.prop.title,
      content: this.prop.content
    }
  }
}

代碼解釋:

第 10 行,約束了泛型參數(shù) T 需繼承自交叉類型(后續(xù)有單節(jié)介紹) Sentence & Music,這樣就能訪問兩個接口類型的參數(shù)。

9. 小結(jié)

泛型在 TypeScript 中用途廣泛,可以靈活的控制類型之間的約束,提高代碼復(fù)用性,增強代碼可讀性。