当前位置: 首页 > news >正文

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 开发者工具箱中不可或缺的重要工具。

相关文章:

  • 【CiteSpace】引文可视化分析软件CiteSpace下载与安装
  • FPGA基础 -- Verilog 锁存器简介
  • 模拟/思维
  • 新发布的一款使用ReactNative新架构加载Svga动画的开源插件[android/ios]
  • RA信号处理
  • 生成https免费证书并绑定到nginx
  • 嵌入式之硬件学习(三)通信方式、串口通信
  • RK3568笔记八十四:rtmp转rtmp直播流测试
  • 亚矩阵云手机+Whatnot:直播电商的自动化增长引擎
  • iOS多端兼容性调试:一次iOS性能优化分工具协作排查过程
  • 上线iOSApp前抓包工具协作保障接口行为一致性(iOS抓包)
  • spring-webmvc @InitBinder 典型用法
  • 《前端面试题:数组操作》
  • PID控制电机
  • springboot入门之路(二)
  • 技术赋能教师专业发展:从理论到实践的深度剖析
  • createInnerAudioContext播放不完整?
  • 榕壹云外卖跑腿系统:基于Spring Boot的开源生活服务平台技术解析
  • STM32 GPIO 寄存器开发
  • OCCT基础类库介绍:Modeling Algorithm - Topological Tools
  • 浙江省专业网站制作网站建设/网站运营管理
  • 诸几建设银行网站/友情链接代码模板
  • 织梦网站地图怎么做/拉新十大推广app平台
  • 岳阳公司网站制作/惠州seo优化服务
  • 东莞营销网站建设哪个平台好/关键词林俊杰mp3在线听
  • wordpress全文/seo 重庆