溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

前端深入理解Typescript泛型概念

發(fā)布時間:2020-10-11 09:12:39 來源:腳本之家 閱讀:136 作者:A000 陌上花開 欄目:web開發(fā)

首先介紹一下泛性的概念

泛型程序設(shè)計(generic programming)是程序設(shè)計語言的一種風(fēng)格或范式。泛型允許程序員在強(qiáng)類型程序設(shè)計語言中編寫代碼時使用一些以后才指定的類型,在實例化時作為參數(shù)指明這些類型。

泛型是指在定義函數(shù),接口或者類的時候,不預(yù)先定義好具體的類型,而在使用的時候在指定類型的一種特性。

先舉一個簡單的例子

假設(shè)我們定義一個函數(shù),它可以接收一個number類型做為參數(shù),并且返回一個number類型。

function genericDemo(data: number): number {
  return data;
}

按照以上的寫法是沒有問題的,但是如果我們要接受一個string并返回一個string呢?如果邏輯一樣還要在寫一遍嗎?就像下面這樣。

function genericDemo(data: string): string {  
  return data;
}

這顯然代碼是很冗余的,我們還有不使用any的寫法嗎?答案是顯然易見的,可以使用范型的寫法,就像下面這樣。

function genericDemo<T>(data: T):T {
  return data;
}

我們在函數(shù)名稱genericDemo后面聲明了范型變量<T>,他用于捕獲調(diào)用該函數(shù)時傳入的參數(shù)類型(例如:number),之后我們就可以使用這個類型。 之后我們再次使用了T當(dāng)做返回值類型。現(xiàn)在我們可以知道參數(shù)類型與返回值類型是相同的了。這允許我們跟蹤函數(shù)里使用的類型的信息。

多個類型參數(shù)

我們在定義范型的時候,也可以一次定義多個類型參數(shù),像下面這樣。

function swap<T, U>(tuple: [T, U]):[U, T] {
  return [tuple[1], tuple[0]];
}

泛型接口

我們先定義一個范型接口Identities,然后定義一個函數(shù)identities()來使用這個范型接口

interface Identities<T, U> {
  id1: T;
  id2: U;
}

我在這里使用T和U作為我們的類型變量來演示任何字母(或有效的字母數(shù)字名稱的組合)都是有效的類型—除了常規(guī)用途之外,您對它們的調(diào)用沒有任何意義。

我們現(xiàn)在可以將這個接口應(yīng)用為identity()的返回類型,修改我們的返回類型以符合它。我們還可以console.log這些參數(shù)和它們的類型,以便進(jìn)一步說明:

function identities<T, U> (arg1: T, arg2: U): Identities<T, U> {
  console.log(arg1 + ": " + typeof (arg1));
  console.log(arg2 + ": " + typeof (arg2));
  let identities: Identities<T, U> = {
  id1: arg1,
  id2: arg2
 };
 return identities;
}

我們現(xiàn)在對identity()所做的是將類型T和U傳遞到函數(shù)和identity接口中,從而允許我們定義與參數(shù)類型相關(guān)的返回類型。

范型變量

使用泛型創(chuàng)建像identity這樣的泛型函數(shù)時,編譯器要求你在函數(shù)體必須正確的使用這個通用的類型。 換句話說,你必須把這些參數(shù)當(dāng)做是任意或所有類型。

我們先看下之前例子

function genericDemo<T>(data: T):T {
  return data;
}

如果我們想同時打印出data的長度。 我們很可能會這樣做

function genericDemo<T>(data: T):T {
  console.log(data.length); // Error: T doesn't have .length
  return data;
}

如果這么做,編譯器會報錯說我們使用了data的.length屬性,但是沒有地方指明data具有這個屬性。 記住,這些類型變量代表的是任意類型,所以使用這個函數(shù)的人可能傳入的是個數(shù)字,而數(shù)字是沒有.length屬性的。

現(xiàn)在假設(shè)我們想操作T類型的數(shù)組而不直接是T。由于我們操作的是數(shù)組,所以.length屬性是應(yīng)該存在的。 我們可以像創(chuàng)建其它數(shù)組一樣創(chuàng)建這個數(shù)組:

function genericDemo<T>(data: Array<T>):Array<T> {
  console.log(data.length);
  return data;
}

范型類

我們還可以在類屬性和方法的意義上使類泛型。泛型類確保在整個類中一致地使用指定的數(shù)據(jù)類型。例如下面這種在React Typescript項目中的寫法。

interface Props {
  className?: string;
  ...
}

interface State {
  submitted?: bool;
  ...
}

class MyComponent extends React.Component<Props, State> {
  ...
}

我們在這里使用與React組件一起使用的泛型,以確保組件的props和state是類型安全的。

泛型約束

我們先看一個常見的需求,我們要設(shè)計一個函數(shù),這個函數(shù)接受兩個參數(shù),一個參數(shù)為對象,另一個參數(shù)為對象上的屬性,我們通過這兩個參數(shù)返回這個屬性的值,比如:

function getValue(obj: object, key: string){
  return obj[key] // error
}

我們會得到一段報錯,這是新手 TypeScript 開發(fā)者常常犯的錯誤,編譯器告訴我們,參數(shù) obj 實際上是 {},因此后面的 key 是無法在上面取到任何值的。

因為我們給參數(shù) obj 定義的類型就是 object,在默認(rèn)情況下它只能是 {},但是我們接受的對象是各種各樣的,我們需要一個泛型來表示傳入的對象類型,比如T extends object:

function getValue<T extends object>(obj: T, key: string) {
 return obj[key] // error
}

這依然解決不了問題,因為我們第二個參數(shù) key 是不是存在于 obj 上是無法確定的,因此我們需要對這個 key 也進(jìn)行約束,我們把它約束為只存在于 obj 屬性的類型,這個時候需要借助到后面我們會進(jìn)行學(xué)習(xí)的索引類型進(jìn)行實現(xiàn) <U extends keyof T>,我們用索引類型 keyof T 把傳入的對象的屬性類型取出生成一個聯(lián)合類型,這里的泛型 U 被約束在這個聯(lián)合類型中,這樣一來函數(shù)就被完整定義了:

function getValue<T extends object, U extends keyof T>(obj: T, key: U) {
 return obj[key] // ok
}

另外提一個多重泛型約束的寫法,可以當(dāng)作拓展:

interface firstInterface {
  first(): number
}

interface secondInterface {
  second(): string
}

class Demo<T extends firstInterface & secondInterface >{
  ...
}

在泛型里使用類類型

在TypeScript使用泛型創(chuàng)建工廠函數(shù)時,需要引用構(gòu)造函數(shù)的類類型。比如:

function create<T>(type: {new(): T; }): T {
  return new type();
}

參數(shù)type的類型{new(): T}就表示此泛型T是可被構(gòu)造的,在被實例化后的類型是泛型 T。

總結(jié)

到此這篇關(guān)于前端深入理解Typescript泛型概念的文章就介紹到這了,更多相關(guān)Typescript 泛型內(nèi)容請搜索億速云以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持億速云!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI