欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

TypeScript泛型的使用詳細(xì)介紹

 更新時(shí)間:2022年09月16日 16:05:35   作者:我是X大魔王  
在TypeScript中,泛型是一種創(chuàng)建可復(fù)用代碼組件的工具。這種組件不只能被一種類(lèi)型使用,而是能被多種類(lèi)型復(fù)用。類(lèi)似于參數(shù)的作用,泛型是一種用以增強(qiáng)類(lèi)(classes)、類(lèi)型(types)和接口(interfaces)能力的非??煽康氖侄?/div>

情景再現(xiàn)

這里針對(duì)一種情況,也是非常常見(jiàn)的一種情況:那就是

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

就是我接收一個(gè)number類(lèi)型的參數(shù),同時(shí)也返回一個(gè)number,那如果現(xiàn)在我想要接收一個(gè)string類(lèi)型,同時(shí)也返回一個(gè)string,那么我就要再寫(xiě)一個(gè)函數(shù)像這樣:

function identity2(arg: string): string{
    return arg;
}

那如果我現(xiàn)在想要void類(lèi)型…??????

可能大家會(huì)想,那全部都變成any不就行了?像下面這樣

function identity(arg: any): any {
    return arg;
}

使用any類(lèi)型會(huì)導(dǎo)致這個(gè)函數(shù)可以接收任何類(lèi)型的arg參數(shù),這樣就丟失了一些信息:傳入的類(lèi)型與返回的類(lèi)型應(yīng)該是相同的。 如果我們傳入一個(gè)數(shù)字,我們只知道任何類(lèi)型的值都有可能被返回。

那這樣不就與我們一開(kāi)始的設(shè)想不一致了嗎?我傳入Number,返回string,也不會(huì)報(bào)錯(cuò)呀!??

因此,我們需要一種方法使返回值的類(lèi)型與傳入?yún)?shù)的類(lèi)型是相同的。 這里,我們使用了類(lèi)型變量,它是一種特殊的變量,只用于表示類(lèi)型而不是值。

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

我們給identity添加了類(lèi)型變量T。 T幫助我們捕獲用戶(hù)傳入的類(lèi)型(比如:number),之后我們就可以使用這個(gè)類(lèi)型。 之后我們?cè)俅问褂昧薚當(dāng)做返回值類(lèi)型?,F(xiàn)在我們可以知道參數(shù)類(lèi)型與返回值類(lèi)型是相同的了。 這允許我們跟蹤函數(shù)里使用的類(lèi)型的信息。

??‍??我們把這個(gè)版本的identity函數(shù)叫做泛型,因?yàn)樗梢赃m用于多個(gè)類(lèi)型。 不同于使用any,它不會(huì)丟失信息,像第一個(gè)例子那像保持準(zhǔn)確性,傳入數(shù)值類(lèi)型并返回?cái)?shù)值類(lèi)型。

使用泛型

第一種是,傳入所有的參數(shù),包含類(lèi)型參數(shù)

第二種方法更普遍。利用了類(lèi)型推論 – 即編譯器會(huì)根據(jù)傳入的參數(shù)自動(dòng)地幫助我們確定T的類(lèi)型

function identity<T>(arg: T): T {
    return arg;
}
let output = identity<string>("myString");
let output2 = identity("myString2"); 
console.log(output);
console.log(output2);

注意我們沒(méi)必要使用尖括號(hào)(<>)來(lái)明確地傳入類(lèi)型;編譯器可以查看myString的值,然后把T設(shè)置為它的類(lèi)型。 類(lèi)型推論幫助我們保持代碼精簡(jiǎn)和高可讀性。如果編譯器不能夠自動(dòng)地推斷出類(lèi)型的話(huà),只能像上面那樣明確的傳入T的類(lèi)型,在一些復(fù)雜的情況下,這是可能出現(xiàn)的。

泛型類(lèi)型

我們研究一下函數(shù)本身的類(lèi)型,以及如何創(chuàng)建泛型接口。

來(lái)看看泛型類(lèi)型不同的展現(xiàn)方式:

function identity<T>(arg: T): T {
    return arg;
}
let myFunction: <T>(arg:T) => T = identity;

我們也可以使用不同的泛型參數(shù)名,只要在數(shù)量上和使用方式上能對(duì)應(yīng)上就可以。

function identity<T>(arg: T): T {
    return arg;
}
let myFunction: <T>(arg:T) => T = identity;
let myIdentity: <U>(arg: U) => U = identity;

我們還可以使用帶有調(diào)用簽名的對(duì)象字面量來(lái)定義泛型函數(shù):

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

是不是花了眼哈哈哈哈哈

泛型接口

還是以上面的為例子噢

interface GenericIdentityFn {
    <T>(arg: T): T;
}
function identity<T>(arg: T): T {
    return arg;
}
let myIdentity: GenericIdentityFn = identity;

可不可以詳細(xì)一點(diǎn)

一個(gè)相似的例子,我們可能想把泛型參數(shù)當(dāng)作整個(gè)接口的一個(gè)參數(shù)。 這樣我們就能清楚的知道使用的具體是哪個(gè)泛型類(lèi)型(比如:Dictionary< string>而不只是Dictionary)。 這樣接口里的其它成員也能知道這個(gè)參數(shù)的類(lèi)型了。

interface GenericIdentityFn<T> {
    (arg: T): T;
}
function identity<T>(arg: T): T {
    return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;

泛型類(lèi)

我等這個(gè)泛型類(lèi)等了好久好久??????

泛型類(lèi)看上去與泛型接口差不多。 泛型類(lèi)使用(<>)括起泛型類(lèi)型,跟在類(lèi)名后面。

// 泛型類(lèi)
class GenericNumber<T> {
    zeroValue: T | undefined;
    add: ((x: T, y: T) => T) | undefined;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
function myAdd(x:number, y:number) { 
    return x + y; 
};
myGenericNumber.add = function(x, y) { 
    return x + y; 
};
console.log(myGenericNumber.add(1,2));

換string玩玩

// 泛型類(lèi)
class GenericNumber<T> {
    zeroValue: T | undefined;
    add: ((x: T, y: T) => T) | undefined;
}
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "hi,";
stringNumeric.add = function(x, y) { return x + y; };
console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

也不是全能的

與接口一樣,直接把泛型類(lèi)型放在類(lèi)后面,可以幫助我們確認(rèn)類(lèi)的所有屬性都在使用相同的類(lèi)型。

注意點(diǎn)??????類(lèi)有兩部分:靜態(tài)部分和實(shí)例部分。 泛型類(lèi)指的是實(shí)例部分的類(lèi)型,所以類(lèi)的靜態(tài)屬性不能使用這個(gè)泛型類(lèi)型。

泛型約束

到底有沒(méi)有長(zhǎng)度啊,救命

當(dāng)我們使用泛型的時(shí)候,有這種情況:

我想要打印出傳過(guò)來(lái)的參數(shù)的長(zhǎng)度為多少

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

這里會(huì)扯到一個(gè)問(wèn)題,首先,你傳過(guò)來(lái)的這個(gè)玩意兒,它本身有長(zhǎng)度嗎??

首先,什么樣的類(lèi)型會(huì)有長(zhǎng)度,毫無(wú)疑問(wèn),數(shù)組嘛

那我如果傳入的不是數(shù)組,那就鐵定報(bào)錯(cuò),就像上面那樣,正確的寫(xiě)法大家也都懂:

function loggingIdentity<T>(arg: T[]): T[] {
    console.log(arg.length);  // Array has a .length, so no more error
    return arg;
}

相比于操作any所有類(lèi)型,我們想要限制函數(shù)去處理任意帶有.length屬性的所有類(lèi)型。 只要傳入的類(lèi)型有這個(gè)屬性,我們就允許,就是說(shuō)至少包含這一屬性。 為此,我們需要列出對(duì)于T的約束要求。

interface Lengthwise {
    length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  // Now we know it has a .length property, so no more error
    return arg;
}

現(xiàn)在傳入一個(gè)數(shù)字試試

傳入數(shù)組:

我們需要傳入符合約束類(lèi)型的值,必須包含必須的屬性:

在泛型里使用類(lèi)類(lèi)型[]

在TypeScript使用泛型創(chuàng)建工廠(chǎng)函數(shù)時(shí),需要引用構(gòu)造函數(shù)的類(lèi)類(lèi)型。

跟在Java中的很像——工廠(chǎng)模式,很是高級(jí)

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

高級(jí)案例

應(yīng)用場(chǎng)景:傳入這個(gè)類(lèi),自動(dòng)創(chuàng)建該類(lèi)并且返回相應(yīng)的屬性。

class BeeKeeper {
    hasMask: boolean = false;
}
class ZooKeeper {
    nametag:string =  "ZooKeeper.nametag";
}
class Animal {
    numLegs: number = 100;
}
class Bee extends Animal {
    keeper: BeeKeeper = new BeeKeeper();
}
class Lion extends Animal {
    keeper: ZooKeeper = new ZooKeeper();
}
function createInstance<A extends Animal>(c: new () => A): A {
    return new c();
}
console.log(createInstance(Lion).keeper.nametag); 
console.log(createInstance(Bee).keeper.hasMask);

到此這篇關(guān)于TypeScript泛型的使用詳細(xì)介紹的文章就介紹到這了,更多相關(guān)TypeScript泛型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論