青训营X豆包MarsCode 技术训练营第五课|TypeScript 类、泛型的使用实践记录|豆包MarsCode AI 刷题

38 阅读3分钟

泛型的基本概念

泛型的核心思想是“类型参数化”。在 TypeScript 中,可以使用尖括号(<>)来定义一个或多个类型参数。例如,下面是一个简单的泛型函数,它接受一个数组并返回数组的第一个元素:

function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}

在这个例子中, 是一个类型参数,表示我们可以传入任何类型的数组。函数的返回值类型也是 T,这意味着返回的元素类型与输入数组的元素类型相同。

泛型的使用场景

1. 函数的泛型

泛型函数是泛型最常见的使用场景之一。通过使用泛型,可以编写更通用的函数。例如,下面的 identity 函数可以接受任何类型的参数并返回相同类型的值:

function identity<T>(arg: T): T {
return arg;
}

这种方式使得 identity 函数可以处理不同类型的数据,而不需要为每种类型编写不同的函数。

2. 类的泛型

泛型不仅可以用于函数,也可以用于类。通过定义泛型类,我们可以创建可以处理多种类型的对象。例如,下面是一个简单的栈(Stack)类的实现:

class Stack<T> {
private items: T[] = [];
push(item: T): void {
    this.items.push(item);
}
pop(): T | undefined {
    return this.items.pop();
}
}

在这个例子中,Stack 类使用了类型参数 T,这使得我们可以创建一个可以存储任何类型的栈。例如,我们可以创建一个存储数字的栈和一个存储字符串的栈:

const numberStack = new Stack<number>();
const stringStack = new Stack<string>();

3. 接口的泛型

泛型接口允许我们定义可以接受类型参数的接口。这在处理复杂数据结构时非常有用。例如,下面是一个简单的泛型接口 Pair,它表示一对值:

interface Pair<K, V> {
key: K;
value: V;
}

可以使用这个接口来创建不同类型的键值对:

const numberStringPair: Pair<number, string> = { key: 1, value: "one" };
const stringBooleanPair: Pair<string, boolean> = { key: "isActive", value: true };

类型约束

在使用泛型时,类型约束可以帮助我们限制类型参数的范围,从而提高代码的安全性。例如,我们可以使用 extends 关键字来约束类型参数,使其必须是某个特定类型的子类型。下面是一个示例,展示了如何使用类型约束来确保类型参数是一个对象,并且具有特定的属性:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}

在这个例子中,K 是一个类型参数,它被约束为 T 的键。这样,我们可以确保在调用 getProperty 函数时,传入的键是对象中存在的属性。

总结

通过对 TypeScript 泛型的学习和实践,我深刻体会到泛型在提高代码复用性和类型安全性方面的重要性。泛型使得我们能够编写更加灵活的代码,减少了重复代码的编写,同时也降低了因类型不匹配而导致的错误。泛型是TypeScript 中一个非常强大的特性,它允许我们在定义函数、类或接口时,不预先指定具体的类型,而是使用类型参数来表示。这样可以使代码更加灵活和可重用,同时也能提高类型安全性。