9. TypeScript 泛型

TypeScript 中的泛型使開發者能夠編寫靈活、可重用的代碼,同時保持類型安全。它們允許動態定義類型,確保函數、類和接口可以適用于任何數據類型。這有助于避免重復,提高代碼的模塊化,使其既類型安全又具備適應性。

一、認識泛型

當程序員需要創建可重用組件時,可以使用 TypeScript 的泛型類型,因為它們用于創建可以處理各種數據類型的組件,并提供類型安全性。可重用組件可以是類、函數和接口。TypeScript 泛型可以以多種方式使用,例如函數泛型、類泛型和接口泛型。

(一) 語法

function functionName<T> (returnValue : T) : T {return returnValue;
}

(二) 用法示例

1. 例一

在這個例子中,我們創建了一個可以接受任意類型數據的泛型函數。我們只需要在參數中傳入任何類型的數據,然后就可以通過 reverseArray 函數對該值進行反轉。

function reverseArray<T>(array: T[]): T[] {return array.reverse();
}const strArray: string[] = reverseArray(["Java", "Python", "C++"]);
const numArray: number[] = reverseArray([1, 2, 3, 4, 5]);
const boolArray: boolean[] = reverseArray([false, true]);console.log(strArray);
console.log(numArray);
console.log(boolArray); 

輸出:

[ 'C++', 'Python', 'Java' ]
[ 5, 4, 3, 2, 1 ]
[ true, false ]

2. 例二

在這個例子中,我們創建了一個泛型接口,通過它我們創建了一個對象和字符串類型的值,并將它們打印在控制臺中。

// 定義一個泛型接口 Resource,T 是類型參數
interface Resource<T> {id: number;               // 資源 IDresourceName: string;     // 資源名稱data: T;                  // 泛型數據字段,類型由使用者決定
}// 使用對象類型實現泛型接口
const person: Resource<object> = {id: 1,                    // 資源 ID 為 1resourceName: 'Person',   // 資源名稱為 "Person"data: {                   // data 是一個對象類型name: 'John',         // 姓名age: 25               // 年齡}
}
console.log(person);          // 打印 person 對象// 使用字符串數組類型實現泛型接口
const employee: Resource<string[]> = {id: 2,                      // 資源 ID 為 2resourceName: 'Employee',   // 資源名稱為 "Employee"data: ['Employee 1', 'Employee 1']  // data 是一個字符串數組
}
console.log(employee);          // 打印 employee 對象

輸出:

{"id": 1,"resourceName": "Person","data": {"name": "John","age": 25}
} 
{"id": 2,"resourceName": "Employee","data": ["Employee 1","Employee 1"]
} 

二、泛型函數

TypeScript 泛型函數允許你創建可以處理多種類型的數據的函數,同時保持類型安全。通過使用尖括號(<T>)中定義的類型參數,泛型使函數能夠在不同的數據類型上運行,而不會失去 TypeScript 類型檢查所帶來的優勢。

(一) 語法

function functionName<T>(parameterName: T): ReturnType {// 函數實現
}

這里:

  • functionName 是你的泛型函數的名稱。
  • <T> 是類型參數 T,它允許你在函數內部處理不同的數據類型。
  • parameterName 表示函數參數的名稱,T 指定該參數接受的數據類型。
  • ReturnType 指定函數預期返回值的類型。

(二) 用法示例

1. 例一

TypeScript 中帶有單個類型參數的泛型函數能夠處理多種數據類型,同時保證類型安全。你可以顯式指定類型,也可以讓 TypeScript 推斷參數和返回值的類型。

function foo<T>(arg: T): T {return arg;
}let result1: string = foo<string>("TYPESCRIPT");
let result2: number = foo<number>(740);
let result3: boolean = foo<boolean>(false);console.log(result1);
console.log(result2);
console.log(result3);

輸出:

GEEKSFORGEEKS
740
false

2. 例二

帶有數組參數的泛型函數允許你處理不同類型的數組。通過使用類型參數,該函數可以處理各種元素類型的數組,同時保持類型安全。

function arrayEl<T>(arr: T[]): void {for (const x of arr) {console.log(x);}
}let elements: number[] = [101, 102, 103];
arrayEl(elements);let elements1: string[] = ["吃飯", "睡覺", "打豆豆"];
arrayEl(elements1);

輸出:

101
102
103
吃飯
睡覺
打豆豆

3. 例三

在這個例子中,函數 mergeArrays 將兩種不同類型的數組合并為一個。它接收類型為 T 和 U 的數組,返回類型為 (T | U)[] 的數組。

function mergeArrays<T, U>(arr1: T[], arr2: U[]): (T | U)[] {return [...arr1, ...arr2];
}// 不同類型的數組
const numbers: number[] = [1, 2, 3];
const words: string[] = ["hello", "world"];// 合并不同類型的數組
const mergedArray: (number | string)[] = mergeArrays(numbers, words);// 輸出合并后的數組
console.log(mergedArray);

輸出:

[1, 2, 3, "hello", "world"]

(三) 總結

在 TypeScript 中,泛型函數允許你構建能夠處理不同數據類型的通用函數,同時確保代碼的類型安全,避免錯誤。這種靈活性非常實用,尤其是在你希望創建能夠應對多種情況而無需重復代碼的函數時。無論是處理數組、對象還是其他數據結構,泛型函數都能幫助你編寫更簡潔、更安全的代碼。

三、泛型約束

在 TypeScript 中,泛型約束(Generic Constraints)通過使用 extends 關鍵字來限制可以與泛型類型一起使用的類型。這確保了泛型類型遵循特定的結構或接口,從而能夠在泛型中訪問某些屬性或方法。

(一) 什么是泛型約束?

  • TypeScript 的泛型使我們能夠編寫可重用的代碼,能夠處理不同的數據類型。我們可以創建可以與不同數據類型一起工作的函數、類或接口。
  • 泛型使用 <T> 的形式定義,這種 T 類型可以用于函數參數、返回值等的類型定義。
  • 泛型約束用于對泛型類型參數可使用的類型施加限制。
  • 這種限制帶來了類型檢查,確保變量在被使用之前具備某種類型的值。
  • 這種檢查機制有助于最大限度地減少運行時錯誤的發生。

語法:

function genericConstraintFunction<T extends GenericConstraintType>(param: T): void {// ...
}

含義如下:

  • T 是泛型類型參數。
  • extends GenericConstraintType 指定了一個約束條件,要求類型參數 T 必須繼承或符合 GenericConstraintType 類型的結構。

(二) 用法示例

1. 例一

在此示例中,Sports 接口具有一個 name 屬性。printSportName 函數使用 extends 來確保其參數在執行前符合 Sports 類型的結構。

// 使用 name 屬性定義 Sports 接口
interface Sports {name: string;
}// 定義函數,確保傳入的類型 T 繼承自 Sports
function printSportName<T extends Sports>(sport: T): void {console.log(sport.name); // 輸出運動名稱
}// 創建一個 Sports 類型的對象
let sport: Sports = { name: "棒球" };// 使用 sport 對象調用函數
printSportName(sport);

輸出:

baseball

2. 例二

在此示例中,我們使用 extends keyof 來確保泛型類型參數 K 是類型 T 的一個鍵。這種做法強制要求 K 必須是 T 的一個有效屬性。

interface Sports {name: string;players: number;
}// 泛型函數,限制 T 必須擴展自 Sports,K 必須是 T 的鍵
function getNumberOfPlayers<T extends Sports, K extends keyof T>(sport: T, players: K): T[K] {return sport[players];}let sport: Sports = { name: "baseball", players: 9 };// 'players' 被推斷為 number 類型
let players: number = getNumberOfPlayers(sport, 'players');
console.log(`球員人數為:${players}`);

輸出:

球員人數為:9

3. 例三

在此示例中,我們確保泛型類型參數的類對象實現了特定的接口。

// 定義一個接口 Sports
interface Sports {name: string;players: number;getNumberOfGloves(): number; // 獲取手套數量的方法
}// 定義一個實現 Sports 接口的類 Baseball
class Baseball implements Sports {constructor(public name: string, public players: number) { }// 實現接口中的方法getNumberOfGloves(): number {return this.players * 2;}
}// 定義一個泛型函數,約束類型 T 必須實現 Sports 接口
function getNumberOfGloves<T extends Sports>(sport: T): void {console.log(`所需手套數量為:${sport.getNumberOfGloves()}`);
}// 創建 Baseball 類的實例
let baseball = new Baseball("baseball", 9);
getNumberOfGloves(baseball); // 輸出:所需手套數量為:18

輸出:

所需手套數量為:18

四、泛型接口

在 TypeScript 中創建帶有泛型類型的接口是一項強大的功能,它提升了代碼的靈活性和可復用性。通過定義帶有泛型類型參數的接口,你可以創建適用于多種數據類型的組件,同時保持類型安全。

(一) 帶有單一泛型類型參數的接口

interface InterfaceName<T> {// 接口成員
}

定義一個帶有單一泛型類型參數的接口,可以創建通用組件,這些組件能夠在不同數據類型間靈活操作。此方法提升了代碼的靈活性,并通過抽象具體的數據實現,促進代碼的重用。

下面的代碼創建了一個帶有單個泛型類型參數的接口。

interface Box<T> {getItem(): T;setItem(item: T): void;
}class MyBox<T> implements Box<T> {private item: T;getItem(): T {return this.item;}setItem(item: T): void {this.item = item;}
}const stringBox: Box<string> = new MyBox<string>();
stringBox.setItem("Hello, Generics!");
console.log("字符串的值:", stringBox.getItem());

輸出:

字符串的值:Hello, Generics!

(二) 多泛型類型參數

TypeScript 也支持帶有多個泛型類型參數的接口,使開發者能夠設計高度可定制且參數化的組件。

下面的代碼創建了一個帶有多個泛型類型參數的接口。

interface Pair<K, V> {key: K;value: V;
}const pair: Pair<number, string> = { key: 1, value: "One" };
console.log("Key:", pair.key, ", Value:", pair.value);

輸出:

Key: 1,  Value: One 

五、泛型與類

TypeScript 中在泛型中使用類類型,可以讓你通過指定泛型參數為類的構造函數,創建更靈活且可重用的代碼。當你想操作類的實例,同時又希望保持類型安全時,這種方式特別有用。你可以定義一個接受類構造函數的泛型類型,然后使用該類型來創建和操作這些類的實例。

(一) 語法

function createInstance<T>(constructor: new (...args: any[]) => T,...args: any[]
): T {// 創建并返回指定類的實例return new constructor(...args);
}

說明:

  • T 是一個泛型類型參數,表示要創建的實例的類型。它允許你指定工廠函數的期望返回類型。
  • constructor 是類構造函數的引用。
  • new (...args: any[]) => T 表示該構造函數可以接受任意數量的參數(...args: any[]),并返回類型為 T 的實例。
  • ...args: any[] 使用剩余參數語法,接受任意數量的額外參數,這些參數會在創建實例時傳遞給構造函數。

(二) 用法示例

1. 例一

在這個例子中,我們定義了一個名為 createInstance 的泛型工廠函數。它接受一個類的構造函數(constructor)和任意數量的附加參數(...args)。createInstance 函數通過使用傳入的參數調用構造函數,創建并返回指定類的實例。

// 定義一個泛型工廠函數
function createInstance<T>(constructor:new (...args: any[]) => T, ...args: any[]): T {return new constructor(...args);
}// 示例類
class Product {constructor(public name: string,  // 產品名稱public price: number) { }  // 產品價格
}class Person {constructor(public name: string,  // 人名public age: number) { }  // 年齡
}// 使用工廠函數創建實例
const laptop = createInstance(Product, 'Laptop', 999);
console.log(laptop);const user = createInstance(Person, 'TypeScript', 30);
console.log(user);

輸出:

Product { name: 'Laptop', price: 999 }
Person { name: 'TypeScript', age: 30 }

2. 例二

在這個例子中,我們定義了一個基類 Animal,包含一個 name 屬性和一個 makeSound 方法。Dog 類繼承自 Animal,新增了 breed 屬性并重寫了 makeSound 方法。我們創建了一個泛型函數 printAnimalInfo,該函數接受一個類型為 T 的參數,且 T 必須繼承自 Animal 類。這意味著它可以接受 Animal 類或其子類的實例。然后我們創建了 Animal 和 Dog 的實例,并分別調用 printAnimalInfo 函數。

// 定義基類 Animal
class Animal {// 構造函數,初始化公開屬性 nameconstructor(public name: string) { }// 返回動物發出的通用聲音makeSound(): string {return "Some generic animal sound";}
}// 定義繼承自 Animal 的子類 Dog
class Dog extends Animal {// 構造函數,接收 name 和 breed 兩個參數constructor(name: string, public breed: string) {super(name);  // 調用父類構造函數,初始化 name}// 重寫父類的 makeSound 方法,返回狗叫聲makeSound(): string {return "Woof! Woof!";}
}// 定義泛型函數,要求類型 T 繼承自 Animal
function printAnimalInfo<T extends Animal>(animal: T): void {// 打印動物的名字console.log(`Name: ${animal.name}`);// 打印動物的叫聲(調用 makeSound 方法)console.log(`Sound: ${animal.makeSound()}`);}// 創建 Animal 類的實例
const genericAnimal = new Animal("Generic Animal");
// 創建 Dog 類的實例
const myDog = new Dog("Buddy", "Golden Retriever");// 使用泛型函數,分別傳入 Animal 和 Dog 實例
printAnimalInfo(genericAnimal);
printAnimalInfo(myDog);

輸出:

Name: Generic Animal
Sound: Some generic animal sound
Name: Buddy
Sound: Woof! Woof!

六、泛型對象類型

TypeScript 泛型對象類型允許你為對象創建靈活且可復用的類型定義。這些泛型類型可以處理不同結構的對象,同時保證類型安全,確保代碼既健壯又具有適應性。它們特別適合用于創建能夠處理多種對象結構的函數或類,同時保持類型的正確性。

(一) 語法

type MyGenericObject<T> = {key: string;value: T;
};

(二) 用法示例

1. 鍵值對

在此示例中,我們創建了一個泛型對象類型來表示鍵值對。類型參數 T 表示值的類型,使得可以使用不同的數據類型。

type KeyValuePair<T> = {key: string;value: T;
};const stringPair: KeyValuePair<string> = { key: 'name', value: 'John' };
const numberPair: KeyValuePair<number> = { key: 'age', value: 30 };console.log(stringPair);
console.log(numberPair);

輸出:

{ key: 'name', value: 'John' }
{ key: 'age', value: 30 }

2. 封裝數據屬性

在此示例中,我們定義了一個泛型對象類型,用于封裝指定類型 T 的數據屬性。這個例子展示了泛型對象類型如何存儲和訪問不同的數據類型。

type DataContainer<T> = {data: T;
};const numericData: DataContainer<number> = { data: 25 };
const stringData: DataContainer<string> = { data: 'TypeScript' };console.log(numericData.data);
console.log(stringData.data);

輸出:

25
TypeScript

(三) 總結

TypeScript 的泛型對象類型提供了一種強大的方式來創建靈活、可復用且類型安全的對象定義。通過利用這些類型,你可以構建更健壯且適應性更強的代碼,確保函數和類能夠處理不同的對象結構,同時保持嚴格的類型正確性。這種方法提升了代碼的可維護性,降低了出錯的風險,成為 TypeScript 開發者工具箱中不可或缺的重要工具。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/84066.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/84066.shtml
英文地址,請注明出處:http://en.pswp.cn/web/84066.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Apache Iceberg與Hive集成:分區表篇

一、Iceberg分區表核心概念與Hive集成原理 1.1 分區表在大數據場景的價值 在大規模數據分析中&#xff0c;分區表通過將數據按特定維度&#xff08;如時間、地域、業務類型&#xff09;劃分存儲&#xff0c;可顯著提升查詢效率。Apache Iceberg的分區表設計融合了Hive的分區理…

SAST + IAST + DAST 全鏈路防護體系構建方案

&#x1f525;「炎碼工坊」技術彈藥已裝填&#xff01; 點擊關注 → 解鎖工業級干貨【工具實測|項目避坑|源碼燃燒指南】 1. 生命周期分層嵌入&#xff08;防御縱深&#xff09; 階段工具防護重點集成觸發點編碼階段SAST源碼漏洞&#xff08;硬編碼密鑰、SQL注入模式&#x…

pnpm link如何不踩坑

前提一&#xff1a;我有一個source-project源碼庫&#xff0c;有一個develop-project項目庫。想使用pnpm link對source-project進行本地調試。 前提二&#xff1a;source-project源碼庫已打包 本地調試詳細步驟如下&#xff1a; 1、檢查是否配置了系統環境變量&#xff0c;P…

vue3 javascript 多字段求和技巧

在 Vue 3 中&#xff0c;如果你需要在一個組件中處理多個字段的求和&#xff0c;你可以通過計算屬性&#xff08;computed properties&#xff09;或者方法&#xff08;methods&#xff09;來實現。這里我將展示兩種主要的方法&#xff1a; 方法 1&#xff1a;使用計算屬性&am…

【LeetCode】每日一題 —— No.3405

LeetCode 3405 統計恰好有 K 個相等相鄰元素的數組數目&#xff08;DP 構造型&#xff09; 題目概述 我們需要統計長度為 n 的數組 arr 滿足如下條件的方案數&#xff1a; 每個元素在區間 [1, m] 之間恰好存在 k 個位置 i (1 ≤ i < n) 滿足 arr[i] arr[i - 1] 也就是說…

Elsa Workflows: .NET 的開源工作流引擎簡介

文章目錄 Elsa Workflows&#xff1a; .NET 的開源工作流引擎核心定位與理念關鍵特性與優勢當前 (Elsa 3) 的已知限制/待完善項總結 Elsa Workflows&#xff1a; .NET 的開源工作流引擎 Elsa Workflows 是一個開源的、模塊化的 .NET 庫集合&#xff0c;旨在為 .NET 應用程序提…

linux虛擬機yum命令報錯解決方案

問題 假如出現了這樣的問題&#xff0c;可能是虛擬機yum庫存在問題 解決方法 1、打開cmd&#xff0c;輸入ssh root地址&#xff0c;比如ssh root192.168.222..111&#xff0c;選yes&#xff0c;輸入虛擬機密碼 2、使用yum repolist,查看倉庫狀態&#xff0c;status下面如果是…

C++ 第一階段 基本語法 - 第一節:變量與數據類型詳解

目錄 一、變量與數據類型概述 1.1 什么是變量&#xff1f; 1.2 數據類型分類 二、基本數據類型詳解 2.1 整型&#xff08;int, short, long&#xff09; 2.1.1 常見整型類型 2.1.2 代碼示例 2.1.3 注意事項 2.2 浮點型&#xff08;float, double&#xff09; 2.2.1 浮…

CppCon 2017 學習:CNL: A Compositional Numeric Library

你說的這段關于浮點數的問題總結得很精準&#xff0c;我幫你整理一下&#xff0c;讓理解更清晰&#xff1a; The Problem with Floating-Point&#xff08;浮點數的問題&#xff09; 復雜的表示結構 浮點數由符號位 &#xff0c;有效數&#xff08;significand/mantissa&…

linux基礎重定向及組合重定向

一、基礎重定向操作符 ?類別? ?操作符? ?含義? ?示例? ?備注? ?標準輸出? > 覆蓋寫入 stdout 到文件 ls > file.txt 文件不存在則創建&#xff0c;存在則清空內容 >> 追加 stdout 到文件末尾 date >> log.txt 保留原有內容 ?標準…

佰力博科技與您探討鐵電分析儀適用場景

鐵電分析儀是一種用于測試和研究鐵電材料性能的精密儀器&#xff0c;其適用場景非常廣泛&#xff0c;涵蓋了材料科學、物理學、電子工程等多個領域。 1、材料科學與工程 鐵電分析儀廣泛應用于鐵電材料的研究&#xff0c;包括薄膜、厚膜、塊體材料以及電子陶瓷等。它能夠測試材料…

JVM 內存模型與垃圾回收機制全解析:架構、算法、調優實踐

Java 作為一門面向對象的編程語言&#xff0c;其核心優勢之一是 “一次編寫&#xff0c;到處運行” 的跨平臺特性。這一特性背后&#xff0c;Java 虛擬機&#xff08;JVM&#xff09;扮演著至關重要的角色。JVM 不僅負責解釋執行字節碼&#xff0c;還通過內存管理和垃圾回收機制…

自然語言處理相關基本概念

基本概念章節總結 一、語言學&#xff08;Linguistics&#xff09; 定義 研究語言的本質、結構和發展規律的科學&#xff0c;涵蓋語音、文字、語法等屬性。分支包括歷時語言學、共時語言學、描述語言學等。 核心內容 分析語言的形態、句法、語義等層面&#xff0c;如詞素&…

Vue購物車應用實現教程

文章目錄 1. 項目介紹2. 開發環境準備3. 設計購物車界面4. 創建Vue實例和數據模型5. 實現購物車功能5.1 從本地存儲加載數據5.2 監聽數據變化保存到本地存儲5.3 實現全選/反選功能5.4 計算選中商品的總價和總數量5.5 實現修改商品數量功能5.6 實現刪除商品功能5.7 實現結算功能…

雙因子認證如何讓Windows系統登錄更安全?SLA操作系統雙因素認證解決方案深度解析

引言&#xff1a;數字化轉型下的身份認證危機 在云計算與遠程辦公普及的2025年&#xff0c;企業信息系統正面臨前所未有的安全挑戰。微軟Azure Virtual Desktop漏洞事件、Citrix數據泄露等安全事件頻發&#xff0c;暴露出傳統密碼認證體系的致命缺陷。據《2025年云安全威脅報告…

FPGA基礎 -- Verilog語言要素之值集合

一、Verilog 值集合&#xff08;Value Set&#xff09; Verilog 是一種面向硬件建模的描述語言&#xff0c;為了更真實地模擬硬件行為&#xff0c;它并不僅僅像 C 語言那樣只有 0 和 1 兩種值&#xff0c;而是采用了四值邏輯&#xff08;Four-valued logic system&#xff09;…

開源一個芯片自由的脫機下載器

一、什么是脫機下載器 簡單來說&#xff0c;脫機下載器就是在不連接電腦、不用專業軟件的情況下&#xff0c;也能幫你把程序燒錄進芯片的工具。只要插上電源、按個按鈕&#xff0c;固件就自動下載進 MCU&#xff0c;非常適合量產、售后、維修等場景。 二、芯片自由的背后&…

Rust 學習筆記:關于模式匹配的練習題

Rust 學習筆記&#xff1a;關于模式匹配的練習題 Rust 學習筆記&#xff1a;關于模式匹配的練習題問題一問題二問題三 Rust 學習筆記&#xff1a;關于模式匹配的練習題 參考視頻&#xff1a; https://www.bilibili.com/video/BV1YxojYJESm 問題一 以下代碼能否通過編譯&…

利用tkinter函數構造MD5加密的可視化操作界面

GitHub文檔地址&#xff1a; https://github.com/gao7025/auto_entry_md5.git 引言 利用tkinter構造一個圖形界面的創建函數&#xff0c;主要實現了文件選擇、MD5加密處理、結果預覽和下載等功能。下面是主要涉及的功能模塊&#xff1a;主框架、文件選擇部分、MD5加密部分、結…

ICEM CFD網格生成 | 基本概念與界面工具

基本概念◆ 名稱定義 網格&#xff1a;網格是空間離散的單元&#xff0c;用于如下數值仿真 結構 流體 電磁 其他 單元 0D – 節點單元 質量點 約束&#xff0c;加載位置 1D –線單元 Bars, beams, rods, springs 2D 網格邊界 2D – 表面/殼單元 - 四邊形 - 三角…