最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何通俗的解釋TypeScript 泛型

 更新時(shí)間:2021年05月06日 10:38:22   作者:淺笑·  
這篇文章主要介紹了TypeScript 泛型,對(duì)泛型感興趣的同學(xué),可以參考下

概述

在 TypeScript 中我們會(huì)使用泛型來(lái)對(duì)函數(shù)的相關(guān)類(lèi)型進(jìn)行約束。這里的函數(shù),同時(shí)包含 class 的構(gòu)造函數(shù),因此,一個(gè)類(lèi)的聲明部分,也可以使用泛型。那么,究竟什么是泛型?如果通俗的理解泛型呢?

什么是泛型

泛型(Generics)是指在定義函數(shù)、接口或類(lèi)的時(shí)候,不預(yù)先指定具體的類(lèi)型,而在使用的時(shí)候再指定類(lèi)型的一種特性。

通俗的解釋?zhuān)盒褪穷?lèi)型系統(tǒng)中的“參數(shù)”,主要作用是為了類(lèi)型的重用。從上面定義可以看出,它只會(huì)用在函數(shù)、接口和類(lèi)中。它和js程序中的函數(shù)參數(shù)是兩個(gè)層面的事物(雖然意義是相同的),因?yàn)?typescript 是靜態(tài)類(lèi)型系統(tǒng),是在js進(jìn)行編譯時(shí)進(jìn)行類(lèi)型檢查的系統(tǒng),因此,泛型這種參數(shù),實(shí)際上是在編譯過(guò)程中的運(yùn)行時(shí)使用。之所以稱(chēng)它為“參數(shù)”,是因?yàn)樗邆浜秃瘮?shù)參數(shù)一模一樣的特性。

function increse(param) {
  // ...
}

而類(lèi)型系統(tǒng)中,我們?nèi)绱耸褂梅盒停?/p>

function increase<T>(param: T): T {
  //...
}

當(dāng) param 為一個(gè)類(lèi)型時(shí),T 被賦值為這個(gè)類(lèi)型,在返回值中,T 即為該類(lèi)型從而進(jìn)行類(lèi)型檢查。

編譯系統(tǒng)

要知道 typescript 本身的類(lèi)型系統(tǒng)也需要編程,只不過(guò)它的編程方式很奇怪,你需要在它的程序代碼中穿插 js代碼(在 ts 代碼中穿插 js 代碼這個(gè)說(shuō)法很怪,因?yàn)槲覀冎庇^的感覺(jué)是在 js 代碼中夾雜了 ts 代碼)。

編程中,最重要的一種形式就是函數(shù)。在 typescript 的類(lèi)型編程中,你看到函數(shù)了嗎?沒(méi)有。這是因?yàn)椋蟹盒偷牡胤骄陀泻瘮?shù),只是函數(shù)的形式被 js 代碼給割裂了。typescript 需要進(jìn)行編譯后得到最終產(chǎn)物。編譯過(guò)程中要做兩件事,一是在內(nèi)存中運(yùn)行類(lèi)型編程的代碼,從而形成類(lèi)型檢查體系,也就是說(shuō),我們能夠?qū)?js 代碼進(jìn)行類(lèi)型檢查,首先是 typescript 編譯器運(yùn)行 ts 編程代碼后得到了一個(gè)運(yùn)行時(shí)的檢查系統(tǒng)本文來(lái)自否子戈的播客,運(yùn)行這個(gè)系統(tǒng),從而對(duì)穿插在其中的 js 代碼進(jìn)行類(lèi)型斷言;二是輸出 js,輸出過(guò)程中,編譯系統(tǒng)已經(jīng)運(yùn)行完了類(lèi)型編程的代碼,就像php代碼中 echo js 代碼一樣,php代碼已經(jīng)運(yùn)行了,顯示出來(lái)的是 js 代碼。

從這個(gè)角度看 typescript,你或許更能理解為什么說(shuō)它是JavaScript的超集,為什么它的編譯結(jié)果是 js。

通俗的理解泛型

既然我們理解了 ts 編譯系統(tǒng)的邏輯,那么我們就可以把類(lèi)型的編程和 js 本身的業(yè)務(wù)編程在情感上區(qū)分開(kāi)。我們所講的“泛型”,只存在于類(lèi)型編程的部分,這部分代碼是 ts 的編譯運(yùn)行時(shí)代碼。

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

function increase<T>(param: T): T {
  //...
}

這段代碼,如果我們把 js 代碼區(qū)分開(kāi),然后用類(lèi)型描述文本來(lái)表示會(huì)是怎樣?

// 聲明函數(shù) @type,參數(shù)為 T,返回結(jié)果為 (T): T 
@type = T => (T): T

// 運(yùn)行函數(shù)得到一個(gè)類(lèi)型 F,即類(lèi)型為 (number): number
@F = @type(number)

// 要求 increase 這個(gè)函數(shù)符合 F 這種類(lèi)型,也就是參數(shù)為 number,返回值也為 number 
@@F
function increase(param) { 
  // ... 
} 
@@end

實(shí)際上沒(méi)有 @@F 這種語(yǔ)法,是我編造出來(lái)的,目的是讓你可以從另一個(gè)角度去看類(lèi)型系統(tǒng)。

當(dāng)我們理解泛型是一種“參數(shù)”之后,我們可能會(huì)問(wèn):類(lèi)型系統(tǒng)的函數(shù)在哪里?對(duì)于 js 函數(shù)而言,你可以很容易指出函數(shù)聲明語(yǔ)句和參數(shù),但是 ts 中,這個(gè)部分是隱藏起來(lái)的。不過(guò),我們可以在一些特定結(jié)構(gòu)中,比較容易看到類(lèi)型函數(shù)的影子:

// 聲明一個(gè)泛型接口,這個(gè)寫(xiě)法,像極了聲明一個(gè)函數(shù),我們用描述語(yǔ)言來(lái)形容 @type = T => (T): T
interface GenericIdentityFn<T> {
    (arg: T): T;
}

// 這個(gè)寫(xiě)法,有點(diǎn)像一個(gè)閉包函數(shù),在聲明函數(shù)后,立即運(yùn)行這個(gè)函數(shù),描述語(yǔ)言:@@[T => (T): T](any)
function identity<T>(arg: T): T {
    return arg;
}

// 使用泛型接口,像極了調(diào)用一個(gè)函數(shù),我們用描述語(yǔ)言來(lái)形容 @type(number)
let myIdentity: GenericIdentityFn<number> = identity;

上面這一整段代碼,我們用描述文本重寫(xiě)一遍:

@GenericIdentityFn = T => (T): T

@@[T => (T): T](any)
function identify(arg) {
  return arg
}
@@end

@@GenericIdentityFn(number)
let myIdentity = identity
@@end

我們?cè)陬?lèi)型系統(tǒng)中聲明了兩個(gè)函數(shù),分別是 @GenericIdentityFn 和 @some(匿名函數(shù) @[T => (T): T])。雖然是兩個(gè)函數(shù),但是實(shí)際上,它們的是一模一樣的,因?yàn)?typescript 是結(jié)構(gòu)類(lèi)型,也就是在類(lèi)型檢查的時(shí)候只判斷結(jié)構(gòu)上的每個(gè)節(jié)點(diǎn)類(lèi)型是否相同,而不是必須保持類(lèi)型變量本身的指針相同。@GenericIdentityFn 和 @some 這兩個(gè)函數(shù)分別被調(diào)用,用來(lái)修飾 identify 和 myIdentify,在調(diào)用的時(shí)候,接收的參數(shù)不同,所以導(dǎo)致最終的類(lèi)型檢查規(guī)則是不同的,identify 只要保證參數(shù)和返回值的類(lèi)型相同,至于具體什么類(lèi)型,any。而 myIdentify 除了保證參數(shù)返回值類(lèi)型相同外,還要求類(lèi)型必須是 number。

泛型類(lèi)

除了泛型接口,class 類(lèi)也可以泛型化,即“泛型類(lèi)”,借助泛型類(lèi),我們來(lái)探究一下泛型的聲明和使用的步驟。

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();

前文泛型接口因?yàn)橹皇菫榱思s束函數(shù)的類(lèi)型,所以寫(xiě)的很像函數(shù),實(shí)際上,我們可以用描述語(yǔ)言重新描述一個(gè)泛型接口和泛型類(lèi)。上面的紅色部分,我們用描述語(yǔ)言來(lái)描述:

@GenericNumber = T => class {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

@GenericNumber 這個(gè)函數(shù),以 T 為參數(shù),返回一個(gè) class,在 @type 函數(shù)體內(nèi)多次用到了參數(shù) T。

@GenericIdentityFn = T => interface { 
  (arg: T): T; 
}

我們重新描述了前面的 interface GenericIdentityFn,這樣我們就可以在接口中增加其他的方法。

可以注意到,即使 typescript 內(nèi)置的基礎(chǔ)類(lèi)型,例如 Array,被聲明為泛型接口、泛型類(lèi)之后,這些接口和類(lèi)在使用時(shí)必須通過(guò)<>傳入?yún)?shù),本質(zhì)上,因?yàn)樗鼈兌际呛瘮?shù),只是返回值不同。

其他泛型使用的通俗解釋

接下來(lái)我們要再描述一個(gè)復(fù)雜的類(lèi)型:

class Animal {
    numLegs: number;
}

function createInstance<A extends Animal>(c: new () => A): A {
    return new c();
}

我們姑且不去看 new() 的部分,我們看尖括號(hào)中的 extends語(yǔ)法,這里應(yīng)該怎么理解呢?實(shí)際上,我們面對(duì)的問(wèn)題是,在編譯時(shí),<A extends Animal> 尖括號(hào)中的內(nèi)容是什么時(shí)候運(yùn)行的,是之前,還是之間?

// 到底是
@type = (A extends Animal) => (new() => A): A
@type(T)
// 還是
@type = A => (new() => A): A
@type(T extends Animal)復(fù)

因?yàn)?typescript 是靜態(tài)類(lèi)型系統(tǒng),Animal 是不變的類(lèi),因此,可以推測(cè)其實(shí)在類(lèi)的創(chuàng)建之前,尖括號(hào)的內(nèi)容已經(jīng)被運(yùn)行了。

@type = (A extends Animal) => (new() => A): A

也就是說(shuō),要使用 @type(T) 產(chǎn)生類(lèi)型,首先 T 要滿(mǎn)足 Animal 的結(jié)構(gòu),然后才能得到需要的類(lèi)型,如果 T 已經(jīng)不滿(mǎn)足 Animal 類(lèi)的結(jié)構(gòu)了,那么編譯器會(huì)直接報(bào)錯(cuò),而這個(gè)報(bào)錯(cuò),不是類(lèi)型檢查階段,而是在類(lèi)型系統(tǒng)的創(chuàng)建階段,也就是 ts 代碼的運(yùn)行階段。這種情況被稱(chēng)為“泛型約束”。

另外,類(lèi)似 <A,B> 這樣的語(yǔ)法其實(shí)和函數(shù)參數(shù)一致。

@type = (A, B) => (A|B): SomeType

我們?cè)賮?lái)看 ts 內(nèi)置的基礎(chǔ)類(lèi)型:Array<number>

@Array = any => any[]

結(jié)語(yǔ)

Typescript 中的泛型,實(shí)際上就是類(lèi)型的生成函數(shù)的參數(shù)。本文的內(nèi)容全部為憑空想象,僅適用于對(duì) ts 進(jìn)行理解時(shí)的思路開(kāi)拓,不適用于真實(shí)編程,特此聲明。

以上就是如何通俗的解釋TypeScript 泛型的詳細(xì)內(nèi)容,更多關(guān)于TypeScript泛型的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • javascript 中模板方法單例的實(shí)現(xiàn)方法

    javascript 中模板方法單例的實(shí)現(xiàn)方法

    這篇文章主要介紹了javascript 中模板方法單例的實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下
    2017-10-10
  • 簡(jiǎn)單實(shí)用的網(wǎng)頁(yè)表格特效

    簡(jiǎn)單實(shí)用的網(wǎng)頁(yè)表格特效

    簡(jiǎn)單實(shí)用的網(wǎng)頁(yè)表格特效...
    2006-07-07
  • 淺談微信小程序列表埋點(diǎn)曝光指南

    淺談微信小程序列表埋點(diǎn)曝光指南

    這篇文章主要介紹了微信小程序列表埋點(diǎn)曝光指南,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 整理關(guān)于Bootstrap警示框的慕課筆記

    整理關(guān)于Bootstrap警示框的慕課筆記

    這篇文章主要為大家整理了關(guān)于Bootstrap導(dǎo)航的慕課筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • 用js做一個(gè)小游戲平臺(tái) (一)

    用js做一個(gè)小游戲平臺(tái) (一)

    大體的意思就是想寫(xiě)一些js,使得網(wǎng)頁(yè)上能玩多個(gè)游戲。譬如:貪吃蛇、俄羅斯方塊、推箱子、坦克等等。
    2009-12-12
  • JS實(shí)現(xiàn)動(dòng)態(tài)給圖片添加邊框的方法

    JS實(shí)現(xiàn)動(dòng)態(tài)給圖片添加邊框的方法

    這篇文章主要介紹了JS實(shí)現(xiàn)動(dòng)態(tài)給圖片添加邊框的方法,涉及javascript操作圖片border的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • JS小游戲之宇宙戰(zhàn)機(jī)源碼詳解

    JS小游戲之宇宙戰(zhàn)機(jī)源碼詳解

    這篇文章主要介紹了JS小游戲之宇宙戰(zhàn)機(jī)源碼,是一款非常經(jīng)典的游戲源碼,包含了游戲設(shè)計(jì)中比較常見(jiàn)的邏輯處理,本文附帶了該游戲的完整源碼,需要的朋友可以參考下
    2014-09-09
  • js執(zhí)行時(shí)間查看器

    js執(zhí)行時(shí)間查看器

    這個(gè)腳本用來(lái)計(jì)算當(dāng)前腳本執(zhí)行的運(yùn)行事件,而不是頁(yè)面的執(zhí)行時(shí)間。主要用于分析各個(gè)代碼的執(zhí)行效率。
    2010-06-06
  • JavaScript繼承的特性與實(shí)踐應(yīng)用深入詳解

    JavaScript繼承的特性與實(shí)踐應(yīng)用深入詳解

    這篇文章主要介紹了JavaScript繼承的特性與實(shí)踐應(yīng)用,結(jié)合實(shí)例形式較為深入的分析了javascript繼承相關(guān)概念、特性、原理、用法及操作注意事項(xiàng),需要的朋友可以參考下
    2018-12-12
  • leaflet的開(kāi)發(fā)入門(mén)教程

    leaflet的開(kāi)發(fā)入門(mén)教程

    leaflet是領(lǐng)先的開(kāi)源JavaScript庫(kù)為移動(dòng)設(shè)備設(shè)計(jì)的互動(dòng)地圖。接下來(lái)通過(guò)本文來(lái)給大家介紹下leaflet的開(kāi)發(fā)入門(mén)教程,需要的朋友可以參考下
    2016-11-11

最新評(píng)論

个旧市| 甘孜县| 津南区| 延边| 密云县| 新干县| 南京市| 大城县| 望都县| 车致| 越西县| 含山县| 葵青区| 堆龙德庆县| 鹤庆县| 浠水县| 三都| 铜鼓县| 两当县| 嵊州市| 元谋县| 保靖县| 黄骅市| 宝丰县| 高要市| 白河县| 共和县| 宁德市| 五华县| 嵊泗县| 巴中市| 永福县| 即墨市| 湘潭市| 龙南县| 昆山市| 河西区| 霍邱县| 聊城市| 额尔古纳市| 鄂托克旗|