深入探讀 TypeScript 中的泛型:从基础到进阶应用

TypeScript 是 JavaScript 的超集,它为 JavaScript 添加了类型系统和其他高级特性。泛型是 TypeScript 中的一项强大特性,它允许我们定义可以处理多种类型的函数和类。在本文中,我们将深入探讨 TypeScript 中的泛型,从基础到进阶应用。

  1. 泛型的基本概念

泛型是一种类型参数化的技术,它允许我们定义可以处理多种类型的函数和类。在 TypeScript 中,我们可以使用尖括号(<>)来定义泛型。

例如,下面的函数是一个简单的泛型函数,它可以处理任何类型的值:

typescriptfunction identity&lt;T&gt;(arg: T): T { return arg;}

在这个例子中,我们定义了一个名为 identity 的函数,它有一个类型参数 T。这个函数接受一个类型为 T 的参数 arg,并返回相同的类型 T

我们可以使用这个函数来处理任何类型的值,例如:

typescriptconst result1 = identity(123); // numberconst result2 = identity("hello"); // stringconst result3 = identity({ name: "John" }); // object

  1. 泛型约束

在某些情况下,我们可能希望限制泛型类型的范围,以便更好地控制函数或类的行为。这就是泛型约束的作用。

例如,下面的函数是一个简单的泛型函数,它只能处理具有 length 属性的数组:

typescriptfunction slice&lt;T&gt;(arr: T[], start: number, end: number): T[] { return arr.slice(start, end);}

在这个例子中,我们定义了一个名为 slice 的函数,它有三个类型参数 Tstartend。这个函数接受一个类型为 T 的数组 arr,并返回一个新的数组,其中包含从 startend 的元素。

我们可以使用这个函数来处理具有 length 属性的数组,例如:

typescriptconst result1 = slice([1, 2, 3], 1, 3); // [2, 3]const result2 = slice(["a", "b", "c"], 1, 3); // ["b", "c"]const result3 = slice(["a", "b", "c"], 1); // ["b"]

  1. 泛型类型推断

TypeScript 可以自动推断泛型类型,这可以帮助我们更轻松地使用泛型。

例如,下面的函数是一个简单的泛型函数,它可以处理任何类型的值,并返回其类型:

typescriptfunction getType&lt;T&gt;(arg: T): T { return arg;}

在这个例子中,我们定义了一个名为 getType 的函数,它有一个类型参数 T。这个函数接受一个类型为 T 的参数 arg,并返回相同的类型 T

我们可以使用这个函数来获取任何类型的值的类型,例如:

typescriptconst result1 = getType(123); // numberconst result2 = getType("hello"); // stringconst result3 = getType({ name: "John" }); // object

TypeScript 可以自动推断 result1result2result3 的类型,因为我们已经传递了具体的值。

  1. 泛型类和接口

我们可以使用泛型来定义类和接口,这可以帮助我们更好地控制类和接口的行为。

例如,下面的类是一个简单的泛型类,它可以处理具有 length 属性的数组:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class ArrayWrapper

<t> {  private arr: T[];</t>

constructor(arr: T\[\]) { this.arr = arr; }

get length(): number { return this.arr.length; }

get(index: number): T { return this.arr\[index\]; }

set(index: number, value: T): void { this.arr\[index\] = value; }

push(value: T): void { this.arr.push(value); }

slice(start: number, end: number): T\[\] { return this.arr.slice(start, end); }}

在这个例子中,我们定义了一个名为 ArrayWrapper 的类,它有一个类型参数 T。这个类有一个私有的数组属性 arr,并提供了一些方法来操作数组,例如 getsetpushslice

我们可以使用这个类来处理具有 length 属性的数组,例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
const arr1 = \[1, 2, 3\];const arr2 = \["a", "b", "c"\];

const wrapper1 = new ArrayWrapper(arr1);const wrapper2 = new ArrayWrapper(arr2);

console.log(wrapper1.length); // 3console.log(wrapper2.length); // 3

console.log(wrapper1.get(1)); // 2console.log(wrapper2.get(1)); // "b"

wrapper1.push(4);wrapper2.push("d");

console.log(arr1); // \[1, 2, 3, 4\]console.log(arr2); // \["a", "b", "c", "d"\]

console.log(wrapper1.slice(1, 3)); // \[2, 3\]console.log(wrapper2.slice(1, 3)); // \["b", "c"\]
  1. 泛型的进阶应用

泛型可以帮助我们更好地处理复杂的数据结构和场景,例如:

  • 处理异步操作的返回值:我们可以使用泛型来定义异步操作的返回值类型,例如:

typescript async function fetchData&lt;T&gt;(url: string): Promise&lt;T&gt; { const response = await fetch(url); const data = await response.json(); return data as T; }

  • 处理多个类型的值:我们可以使用泛型来定义处理多个类型的值的函数或类,例如:

typescript function merge&lt;T extends object, U extends object&gt;(obj1: T, obj2: U): { [key: string]: any } { const result: { [key: string]: any } = {}; for (const key in obj1) { result[key] = obj1[key]; } for (const key in obj2) { result[key] = obj2[key]; } return result; }

  • 处理类型的约束:我们可以使用泛型来定义类型的约束,例如:
1
2
3
 type MyArray

<t> = T[] &amp; { length: number };</t>