1. 前言
Typescript编程中,一定少不了定义类型,约束规则目的提高代码质量和好维护,可弊端就是太死板了呀!声明个产量、函数、类、接口,都需要定义类型,太麻烦了吧?
泛型就是缓解这个问题,泛型顾名思义 广泛的、不受约束的嘛,使用泛型可以在ts中定义任意类型数据。相当于升级版的 any。
基本使用
泛型使用尖括号 < >
来表示,并在定义函数、类或接口时指定类型参数。下面是一些基本的使用示例:
// 示例1: 创建一个泛型函数 function identity<T>(arg: T): T { return arg; } // 示例2: 使用泛型函数 let output = identity<string>("Hello"); console.log(output); // 输出: Hello // 示例3: 使用类型推断,自动推断泛型类型 let output2 = identity("Hello"); console.log(output2); // 输出: Hello
在示例1中,函数 identity
使用了泛型类型参数 T
,表示参数和返回值的类型可以是任何类型。示例2和示例3展示了如何使用泛型函数并指定参数的类型。
2. 使用泛型变量:
泛型变量允许我们在函数或类中使用一种不确定的类型,而在实际使用时才确定具体的类型。
举个例子,考虑一个简单的函数identity
,它接受一个参数并返回相同的值:
function identity<T>(arg: T): T { return arg; }
在这个例子中,我们使用了泛型变量T
,它可以代表任意类型。当我们调用函数identity
时,编译器会根据传入的参数类型自动推断T
的具体类型。
例如:
let result = identity<string>("Hello"); console.log(result); // 输出:Hello let value = identity<number>(42); console.log(value); // 输出:42
通过使用泛型变量,函数identity
可以适用于不同类型的参数,提供了更高的灵活性和可重用性。
3. 泛型类型:
泛型类型允许我们创建可以适用于不同类型的变量、函数或类。
举个例子,考虑一个简单的数组反转函数reverse
:
function reverse<T>(array: T[]): T[] { return array.reverse(); }
在这个例子中,我们定义了一个泛型函数reverse
,接受一个数组参数,并返回反转后的数组。泛型类型T
用于指定数组的元素类型。
例如:
let numbers: number[] = [1, 2, 3, 4, 5]; let reversedNumbers = reverse(numbers); console.log(reversedNumbers); // 输出:[5, 4, 3, 2, 1] let strings: string[] = ["apple", "banana", "orange"]; let reversedStrings = reverse(strings); console.log(reversedStrings); // 输出:["orange", "banana", "apple"]
通过使用泛型类型,函数reverse
可以适用于不同类型的数组,提供了更高的灵活性和可重用性。
4. 泛型类:
泛型类允许我们创建可以适用于多种类型的类。类中的成员可以使用泛型类型进行声明和使用。
举个例子,考虑一个简单的Box
类,用于存储任意类型的值:
class Box<T> { private value: T; constructor(value: T) { this.value = value; } getValue(): T { return this.value; } }
在这个例子中,我们定义了一个泛型类Box
,它具有一个私有成员value
和一个公共方法getValue
用于获取值。
例如:
let box1 = new Box<number>(42); console.log(box1.getValue()); // 输出:42 let box2 = new Box<string>("Hello"); console.log(box2.getValue()); // 输出:Hello
通过使用泛型类,我们可以创建适用于不同类型的Box
对象,并且保持类型安全。
5. 泛型约束:
泛型约束允许我们限制泛型类型的范围,使其满足特定条件。
举个例子,假设我们想编写一个函数getLength
,用于获取对象的长度。但是并不是所有的对象都有length
属性,所以我们需要对泛型类型进行约束,确保它具有该属性。
例如:
interface HasLength { length: number; } function getLength<T extends HasLength>(obj: T): number { return obj.length; }
在这个例子中,我们使用泛型约束T extends HasLength
来限制泛型类型T
必须满足HasLength
接口的要求,即具有length
属性。
例如:
let str = "Hello"; console.log(getLength(str)); // 输出:5 let arr = [1, 2, 3, 4, 5]; console.log(getLength(arr)); // 输出:5
通过使用泛型约束,函数getLength
可以接受具有length
属性的对象,并返回其长度。
6 泛型接口:
泛型接口允许我们定义可以适用于不同类型的接口。
举个例子,考虑一个简单的Transformer
接口,它定义了一个将输入值转换为输出值的转换器:
interface Transformer<T, U> { transform(input: T): U; }
在这个例子中,我们定义了一个泛型接口Transformer
,它有两个类型参数T
和U
,用于定义输入类型和输出类型。
例如,我们可以实现一个字符串到数字的转换器:
class StringToNumberTransformer implements Transformer<string, number> { transform(input: string): number { return parseFloat(input); } }
通过定义实现了Transformer
接口的类,我们可以创建不同类型的转换器。
例如:
let transformer = new StringToNumberTransformer(); let result = transformer.transform("3.14"); console.log(result); // 输出:3.14
通过使用泛型接口,我们可以定义可重用、可灵活的接口,适用于不同类型的转换操作。
总结:
泛型在TypeScript中提供了更灵活、可重用的代码编写方式。它可以用于定义函数、类以及接口,让我们能够编写适用于不同类型的代码。