前言
人們經(jīng)常聽(tīng)說(shuō) TypeScript 就是添加了類型和附加功能的 JavaScript,但卻沒(méi)有人談?wù)撨@些“附加功能”,仿佛他們害怕自己會(huì)發(fā)現(xiàn)什么似的。為了提高應(yīng)用程序的靈活性和長(zhǎng)期可擴(kuò)展性,泛型被引入 Web 開(kāi)發(fā)中,作為一種工具來(lái)復(fù)用組件。
什么是 TypeScript 泛型?
這里有這樣一個(gè)有趣的場(chǎng)景:一位 TypeScript 開(kāi)發(fā)者正在和一位 JavaScript 開(kāi)發(fā)者討論他們?cè)?Web 開(kāi)發(fā)中最喜歡使用的功能。聊天中,他們提到了“泛型”這個(gè)詞。JavaScript 開(kāi)發(fā)者感到困惑,問(wèn)泛型是什么。TypeScript 開(kāi)發(fā)者回答說(shuō):“ TypeScript 泛型是 Web 開(kāi)發(fā)中用于創(chuàng)建可復(fù)用組件的工具。它可以幫助開(kāi)發(fā)者創(chuàng)建能夠處理多種數(shù)據(jù)類型的組件,而無(wú)需為特定組件顯式定義每種類型?!?/p>
假設(shè)一位開(kāi)發(fā)人員創(chuàng)建了一個(gè)特定類型的組件number
,但之后在代碼庫(kù)中,他想復(fù)用該組件的功能來(lái)接受其他數(shù)據(jù)類型的輸入,比如string
。TypeScript 泛型無(wú)需切換組件來(lái)接受string
數(shù)據(jù)類型,而是提供了為單個(gè)組件接受多種類型的靈活性。是不是很有意思?所以,如果你一直在尋找實(shí)現(xiàn)這一點(diǎn)的方法,那么你來(lái)對(duì)地方了!
為什么要使用 TypeScript 泛型?
代碼可重用性是使用 TypeScript 泛型的好處之一,但這還不是全部。其他主要好處包括:
- 編譯時(shí)類型檢查:使用泛型時(shí),必須在定義變量、函數(shù)或類后指定數(shù)據(jù)類型。指定的數(shù)據(jù)類型會(huì)在到達(dá)編譯器之前進(jìn)行檢查。這可以節(jié)省開(kāi)發(fā)時(shí)間,因?yàn)轭愋湾e(cuò)誤會(huì)更早地被突出顯示。
- 提高代碼可讀性:在大型項(xiàng)目或團(tuán)隊(duì)合作中,一項(xiàng)關(guān)鍵的工程實(shí)踐是確保代碼易于閱讀。由于 TypeScript 泛型是明確定義的,因此使用泛型可以提高代碼可讀性。
- 消除類型推斷: 泛型不再允許 TypeScript 編譯器通過(guò)類型推斷來(lái)推斷類型,而是消除了類型推斷的需要。這提高了代碼安全性。
- 消除
any
類型:確保變量兼容多種類型的一種方法是賦予其 any 類型。這會(huì)告訴編譯器:“嘿,這個(gè)變量應(yīng)該適用于任何數(shù)據(jù)類型!” 然而,這是一種不好的做法,因?yàn)闆](méi)有進(jìn)行類型檢查,可能會(huì)導(dǎo)致不必要的結(jié)果。泛型提供了一種在確保類型安全的同時(shí)接受多種數(shù)據(jù)類型的方法。
基本語(yǔ)法和工作原理
我們已經(jīng)了解到,使用泛型可以實(shí)現(xiàn)單個(gè)變量接受多種數(shù)據(jù)類型,而不像使用any
關(guān)鍵字那樣??紤]下面的代碼塊:
let size: number = 12;
let size = "Twelve";
在上面的代碼片段中,我們將變量 size 的類型指定為數(shù)值,其值為12
,然后嘗試將變量重新賦值為,但采用字符串格式。由于我們嘗試將變量賦值為類型,而該變量最初被定義為接受數(shù)據(jù)類型12
,因此會(huì)引發(fā)錯(cuò)誤。我們?nèi)绾螌?shí)現(xiàn)一個(gè)實(shí)例,使變量能夠同時(shí)接受和兩種類型?string``Twelve``number``number``string
使用任何數(shù)據(jù)類型
將多種數(shù)據(jù)類型的值賦給單個(gè)變量的一種方法是使用any
數(shù)據(jù)類型。請(qǐng)考慮下面的代碼塊:
//code sample
let sample: any
//string data type
sample =
"Convert from one programming language to another using the Pieces App"
//number data type
sample = 2
sample = true
在這里,我們創(chuàng)建一個(gè)名為 sample 的變量,其any
類型為 。這意味著該變量可以接受任何數(shù)據(jù)類型。在我們的代碼片段中,我們分配了一個(gè)string
類型,表示“使用 Pieces App 從一種編程語(yǔ)言轉(zhuǎn)換為另一種編程語(yǔ)言”,一個(gè)number
類型為 value 2
,以及一個(gè)布爾類型為 value true
。
在 TypeScript 中,將其他數(shù)據(jù)類型的值賦給預(yù)定義變量會(huì)引發(fā)錯(cuò)誤,但 TypeScriptany
提供了解決方案。any
然而,不建議使用 TypeScript 數(shù)據(jù)類型,因?yàn)樗鼤?huì)繞過(guò)類型檢查,并在運(yùn)行時(shí)帶來(lái)類型不匹配的風(fēng)險(xiǎn)。
泛型的使用 - 泛型函數(shù)
TypeScript 允許單個(gè)變量使用多種數(shù)據(jù)類型的另一種方式是使用泛型。泛型函數(shù)構(gòu)成了泛型的主要用途。假設(shè)我們現(xiàn)在在 TypeScript 中創(chuàng)建一個(gè)接受數(shù)字類型的函數(shù)。具體操作如下:
function numberType(arg: number): number {
return arg;
}
這里,為了避免拋出錯(cuò)誤,返回值的類型必須是數(shù)字。有時(shí),我們不知道返回的具體值。使用該any
類型將使函數(shù)接受該值,但我們不知道返回的類型。這就是 TypeScript 中泛型的作用所在。它允許接受任何數(shù)據(jù)類型,同時(shí)指定被接受的類型。讓我們看看如何實(shí)現(xiàn)這一點(diǎn):
function anyType<Type>(arg: Type): Type {
return arg;
}
在上面的代碼片段中,我們添加了一個(gè)Type
嵌入的 Type 變量<>
,這是 TypeScript 泛型的基本語(yǔ)法。當(dāng)函數(shù)返回一個(gè)值時(shí),Type
可以通過(guò) 知道返回的確切類型。這是使用 TypeScript 泛型的好處之一——不再需要any
類型。
創(chuàng)建通用函數(shù)
為了正確理解代碼庫(kù)中泛型的必要性,我們將創(chuàng)建一個(gè)基本的 TypeScript 泛型函數(shù),它接受不同類型的數(shù)據(jù)。正如我們之前討論過(guò)的,實(shí)現(xiàn)這一點(diǎn)的一種方法是使用any
類型。在本節(jié)中,我們將討論如何使用泛型來(lái)實(shí)現(xiàn)這一點(diǎn)。請(qǐng)考慮下面的代碼塊:
function genericsSample<T>(items: T[]): T[] {
return new Array<T>().concat(items);
}
let numType = genericsSample<number>([10, 20, 30]);
let stringType = genericsSample<string>([
"Pieces app",
"A tool for developers",
]);
numType.push(80);
numType.push("Copy and save code snippets");
stringType.push(
"Convert from one programming language to another using the Pieces App",
);
stringType.push(90);
console.log(numType);
console.log(stringType);
在上面的代碼塊中,我們創(chuàng)建了一個(gè)用于連接兩個(gè)元素的泛型函數(shù)。此代碼片段旨在接受兩種類型的數(shù)據(jù):數(shù)字和字符串。此代碼片段與包含泛型的代碼片段的主要區(qū)別any
在于,泛型函數(shù)會(huì)驗(yàn)證用戶的數(shù)據(jù)類型。
在此代碼片段中,我們創(chuàng)建了一個(gè)名為 的泛型函數(shù)genericsSample
,它返回一個(gè)類型數(shù)組。之后,我們創(chuàng)建了兩個(gè)變量,numType
和接受一個(gè)數(shù)字?jǐn)?shù)組,而接受一個(gè)字符串?dāng)?shù)組stringType
。這樣做的目的是在用戶登錄控制臺(tái)之前驗(yàn)證用戶的輸入。numType``stringType
成功創(chuàng)建變量后,我們嘗試向已創(chuàng)建的 TypeScript 通用數(shù)組中添加新項(xiàng),以測(cè)試其是否有效。我們向 和 分別添加了一個(gè)字符串和一個(gè)數(shù)字numType
。stringType
這兩個(gè)字符串分別是“復(fù)制并保存代碼片段” 和“使用 Pieces App 從一種編程語(yǔ)言轉(zhuǎn)換為另一種編程語(yǔ)言”, 它們是 Pieces 的一些用例。
在輸出中,我們看到,當(dāng)我們嘗試將字符串添加到 anumType
以及嘗試將數(shù)字添加到 a 時(shí),它會(huì)拋出一個(gè)錯(cuò)誤stringType
。讓我們運(yùn)行代碼并查看輸出:

在這里,我們看到,第一次將字符串傳遞給 numType 變量時(shí)會(huì)引發(fā)一個(gè)錯(cuò)誤,而將數(shù)字傳遞給 stringType 變量時(shí)又會(huì)引發(fā)另一個(gè)錯(cuò)誤。借助泛型,我們的代碼可以在單個(gè)函數(shù)中驗(yàn)證多種數(shù)據(jù)類型的輸入。
泛型類
除了創(chuàng)建函數(shù)之外,我們還可以創(chuàng)建 TypeScript 泛型類。定義類名后,在尖括號(hào) (<>) 中指定泛型類型參數(shù)。請(qǐng)考慮以下代碼塊:
class GenericClass<T> {
private genericField: T;
constructor(value: T) {
this.genericField = value;
}
getValue(): T {
return this.genericField;
}
}
const numType = new GenericClass<number>(27);
const getNum: number = numType.getValue();
console.log(getNum);
const stringType = new GenericClass<string>(
"Convert from one programming language to another using the Pieces App",
);
const getString: string = stringType.getValue();
console.log(getString);
在這里,為了在我們的類中接受多種類型,我們?cè)?TypeScript 中創(chuàng)建了一個(gè)泛型類,其類型參數(shù)為“T”,這樣我們就可以指定要傳遞給它的任何類型(數(shù)字、字符串或任何其他類型)。在這段代碼的第一個(gè)實(shí)例中,我們指定 GenericClass 的值應(yīng)該是數(shù)字類型 27。在第二個(gè)實(shí)例中,我們指定 GenericClass 的值應(yīng)該是一個(gè)字符串,內(nèi)容為“使用 Pieces App 從一種編程語(yǔ)言轉(zhuǎn)換為另一種編程語(yǔ)言” 。
TypeScript 通用接口
TypeScript 中的接口也支持泛型。這使我們能夠創(chuàng)建接受多種數(shù)據(jù)類型的接口。假設(shè)我們要?jiǎng)?chuàng)建一個(gè)接受兩種類型(數(shù)字和字符串)的泛型 TypeScript 接口。操作方法如下:
interface interfaceSample<T, U> {
first: T;
second: U;
}
const interfaceOne: interfaceSample<number, string> = {
first: 20,
second: "10",
};
const interfaceTwo: interfaceSample<string, boolean> = {
first: "Generate code snippets using Pieces Co Pilot",
second: true,
};
console.log(interfaceOne);
console.log(interfaceTwo);
這里,我們創(chuàng)建一個(gè) TypeScript 泛型接口,其中包含兩個(gè)類型參數(shù)“T”和“U”。這代表我們將要傳入的類型的占位符。在 interfaceOne 變量中,我們傳入數(shù)字類型和字符串類型。在 interfaceTwo 變量中,我們傳入一個(gè)布爾類型和一個(gè)字符串類型,其含義為“使用 Pieces Copilot 生成代碼片段” 。

TypeScript 泛型約束
雖然泛型適用于所有類型,但有時(shí)我們可能希望將函數(shù)、類或接口限制為僅使用單一類型。我們通過(guò)使用 TypeScript 泛型約束來(lái)實(shí)現(xiàn)這一點(diǎn)。我們可以使用一個(gè)示例接口來(lái)演示這一點(diǎn):
interface ConstraintSample {
sample: number;
}
function loggingIdentity<Type extends ConstraintSample>(test: Type): Type {
console.log(test.sample);
return test;
}
loggingIdentity({ sample: 15, value: 10 });
通常,要獲取值 10,我們只需調(diào)用 loggingIdentity(10) 函數(shù)即可,但在本例中,這行不通,因?yàn)槲覀兲砑恿艘粋€(gè)泛型約束,它為我們正在處理的類型增加了額外的特異性。在這里,要獲取值 10,我們必須首先指定我們嘗試調(diào)用的值中有一個(gè) sample 屬性。要調(diào)用約束中的任何值,我們需要指定與該值關(guān)聯(lián)的所有屬性。
轉(zhuǎn)自https://juejin.cn/post/7512642238833557556
該文章在 2025/6/9 11:49:19 編輯過(guò)