TypeScript 中的泛型使开发者能够编写灵活、可重用的代码,同时保持类型安全。它们允许动态定义类型,确保函数、类和接口可以适用于任何数据类型。这有助于避免重复,提高代码的模块化,使其既类型安全又具备适应性。
当程序员需要创建可重用组件时,可以使用 TypeScript 的泛型类型,因为它们用于创建可以处理各种数据类型的组件,并提供类型安全性。可重用组件可以是类、函数和接口。TypeScript 泛型可以以多种方式使用,例如函数泛型、类泛型和接口泛型。
function functionName (returnValue : T) : T {
return returnValue;
}
在这个例子中,我们创建了一个可以接受任意类型数据的泛型函数。我们只需要在参数中传入任何类型的数据,然后就可以通过 reverseArray
函数对该值进行反转。
function reverseArray(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 ]
在这个例子中,我们创建了一个泛型接口,通过它我们创建了一个对象和字符串类型的值,并将它们打印在控制台中。
// 定义一个泛型接口 Resource,T 是类型参数
interface Resource {
id: number; // 资源 ID
resourceName: string; // 资源名称
data: T; // 泛型数据字段,类型由使用者决定
}
// 使用对象类型实现泛型接口
const person: Resource
输出:
{
"id": 1,
"resourceName": "Person",
"data": {
"name": "John",
"age": 25
}
}
{
"id": 2,
"resourceName": "Employee",
"data": [
"Employee 1",
"Employee 1"
]
}
TypeScript 泛型函数允许你创建可以处理多种类型的数据的函数,同时保持类型安全。通过使用尖括号(
)中定义的类型参数,泛型使函数能够在不同的数据类型上运行,而不会失去 TypeScript 类型检查所带来的优势。
function functionName(parameterName: T): ReturnType {
// 函数实现
}
这里:
functionName
是你的泛型函数的名称。
是类型参数 T
,它允许你在函数内部处理不同的数据类型。parameterName
表示函数参数的名称,T
指定该参数接受的数据类型。ReturnType
指定函数预期返回值的类型。TypeScript 中带有单个类型参数的泛型函数能够处理多种数据类型,同时保证类型安全。你可以显式指定类型,也可以让 TypeScript 推断参数和返回值的类型。
function foo(arg: T): T {
return arg;
}
let result1: string = foo("TYPESCRIPT");
let result2: number = foo(740);
let result3: boolean = foo(false);
console.log(result1);
console.log(result2);
console.log(result3);
输出:
GEEKSFORGEEKS
740
false
带有数组参数的泛型函数允许你处理不同类型的数组。通过使用类型参数,该函数可以处理各种元素类型的数组,同时保持类型安全。
function arrayEl(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
吃饭
睡觉
打豆豆
在这个例子中,函数 mergeArrays 将两种不同类型的数组合并为一个。它接收类型为 T 和 U 的数组,返回类型为 (T | U)[] 的数组。
function mergeArrays(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
关键字来限制可以与泛型类型一起使用的类型。这确保了泛型类型遵循特定的结构或接口,从而能够在泛型中访问某些属性或方法。
的形式定义,这种 T 类型可以用于函数参数、返回值等的类型定义。语法:
function genericConstraintFunction(param: T): void {
// ...
}
含义如下:
extends
GenericConstraintType 指定了一个约束条件,要求类型参数 T 必须继承或符合 GenericConstraintType 类型的结构。在此示例中,Sports
接口具有一个 name
属性。printSportName
函数使用 extends
来确保其参数在执行前符合 Sports
类型的结构。
// 使用 name 属性定义 Sports 接口
interface Sports {
name: string;
}
// 定义函数,确保传入的类型 T 继承自 Sports
function printSportName(sport: T): void {
console.log(sport.name); // 输出运动名称
}
// 创建一个 Sports 类型的对象
let sport: Sports = { name: "棒球" };
// 使用 sport 对象调用函数
printSportName(sport);
输出:
baseball
在此示例中,我们使用 extends keyof
来确保泛型类型参数 K
是类型 T
的一个键。这种做法强制要求 K
必须是 T
的一个有效属性。
interface Sports {
name: string;
players: number;
}
// 泛型函数,限制 T 必须扩展自 Sports,K 必须是 T 的键
function getNumberOfPlayers
(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
在此示例中,我们确保泛型类型参数的类对象实现了特定的接口。
// 定义一个接口 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(sport: T): void {
console.log(`所需手套数量为:${sport.getNumberOfGloves()}`);
}
// 创建 Baseball 类的实例
let baseball = new Baseball("baseball", 9);
getNumberOfGloves(baseball); // 输出:所需手套数量为:18
输出:
所需手套数量为:18
在 TypeScript 中创建带有泛型类型的接口是一项强大的功能,它提升了代码的灵活性和可复用性。通过定义带有泛型类型参数的接口,你可以创建适用于多种数据类型的组件,同时保持类型安全。
interface InterfaceName {
// 接口成员
}
定义一个带有单一泛型类型参数的接口,可以创建通用组件,这些组件能够在不同数据类型间灵活操作。此方法提升了代码的灵活性,并通过抽象具体的数据实现,促进代码的重用。
下面的代码创建了一个带有单个泛型类型参数的接口。
interface Box {
getItem(): T;
setItem(item: T): void;
}
class MyBox implements Box {
private item: T;
getItem(): T {
return this.item;
}
setItem(item: T): void {
this.item = item;
}
}
const stringBox: Box = new MyBox();
stringBox.setItem("Hello, Generics!");
console.log("字符串的值:", stringBox.getItem());
输出:
字符串的值:Hello, Generics!
TypeScript 也支持带有多个泛型类型参数的接口,使开发者能够设计高度可定制且参数化的组件。
下面的代码创建了一个带有多个泛型类型参数的接口。
interface Pair {
key: K;
value: V;
}
const pair: Pair = { key: 1, value: "One" };
console.log("Key:", pair.key, ", Value:", pair.value);
输出:
Key: 1, Value: One
TypeScript 中在泛型中使用类类型,可以让你通过指定泛型参数为类的构造函数,创建更灵活且可重用的代码。当你想操作类的实例,同时又希望保持类型安全时,这种方式特别有用。你可以定义一个接受类构造函数的泛型类型,然后使用该类型来创建和操作这些类的实例。
function createInstance(
constructor: new (...args: any[]) => T,
...args: any[]
): T {
// 创建并返回指定类的实例
return new constructor(...args);
}
说明:
...args: any[]
),并返回类型为 T
的实例。在这个例子中,我们定义了一个名为 createInstance 的泛型工厂函数。它接受一个类的构造函数(constructor)和任意数量的附加参数(...args)。createInstance 函数通过使用传入的参数调用构造函数,创建并返回指定类的实例。
// 定义一个泛型工厂函数
function createInstance(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 }
在这个例子中,我们定义了一个基类 Animal,包含一个 name 属性和一个 makeSound 方法。Dog 类继承自 Animal,新增了 breed 属性并重写了 makeSound 方法。我们创建了一个泛型函数 printAnimalInfo,该函数接受一个类型为 T 的参数,且 T 必须继承自 Animal 类。这意味着它可以接受 Animal 类或其子类的实例。然后我们创建了 Animal 和 Dog 的实例,并分别调用 printAnimalInfo 函数。
// 定义基类 Animal
class Animal {
// 构造函数,初始化公开属性 name
constructor(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
(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 = {
key: string;
value: T;
};
在此示例中,我们创建了一个泛型对象类型来表示键值对。类型参数 T 表示值的类型,使得可以使用不同的数据类型。
type KeyValuePair = {
key: string;
value: T;
};
const stringPair: KeyValuePair = { key: 'name', value: 'John' };
const numberPair: KeyValuePair = { key: 'age', value: 30 };
console.log(stringPair);
console.log(numberPair);
输出:
{ key: 'name', value: 'John' }
{ key: 'age', value: 30 }
在此示例中,我们定义了一个泛型对象类型,用于封装指定类型 T 的数据属性。这个例子展示了泛型对象类型如何存储和访问不同的数据类型。
type DataContainer = {
data: T;
};
const numericData: DataContainer = { data: 25 };
const stringData: DataContainer = { data: 'TypeScript' };
console.log(numericData.data);
console.log(stringData.data);
输出:
25
TypeScript
TypeScript 的泛型对象类型提供了一种强大的方式来创建灵活、可复用且类型安全的对象定义。通过利用这些类型,你可以构建更健壮且适应性更强的代码,确保函数和类能够处理不同的对象结构,同时保持严格的类型正确性。这种方法提升了代码的可维护性,降低了出错的风险,成为 TypeScript 开发者工具箱中不可或缺的重要工具。