Skip to content

泛型 (Generics)

泛型是 TypeScript 中一个非常强大的特性,它允许你编写更加灵活和可重用的代码。通过泛型,你可以定义函数、接口或类时指定一个或多个类型参数,这些参数可以在使用时被具体化为实际的类型。这不仅提高了代码的复用性,还增强了类型安全性。

基本概念

  • 类型参数:在定义泛型时使用的占位符,用于表示将来会被具体化的类型。
  • 类型推断:当调用泛型函数或实例化泛型类时,TypeScript 可以根据传入的参数自动推断出具体的类型。
  • 约束:可以对类型参数进行约束,确保它们符合特定的类型结构。

示例解析

示例 1: 简单的泛型函数

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

console.log(identity<string>("hello")); // 输出: "hello"
console.log(identity<number>(42)); // 输出: 42

在这个例子中,identity 函数接受一个类型参数 T,它可以是任何类型。返回值的类型也是 T,即与输入参数的类型相同。

示例 2: 使用泛型约束

有时你可能希望限制泛型参数的类型范围,确保它们至少具有某些属性或方法。这时可以使用泛型约束。

typescript
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length); // 现在我们知道 arg 有 length 属性
  return arg;
}

loggingIdentity({ length: 10, value: "hello" });

在这个例子中,T 被约束为必须实现 Lengthwise 接口,因此我们可以安全地访问 arg.length 属性。

示例 3: 多个类型参数

你可以定义多个类型参数来处理更复杂的场景。

typescript
function swap<T, U>(tuple: [T, U]): [U, T] {
  return [tuple[1], tuple[0]];
}

console.log(swap([1, "hello"])); // 输出: ["hello", 1]

示例 4: 默认类型参数

TypeScript 允许你为泛型参数提供默认类型,这样如果调用时不指定类型参数,将使用默认类型。

typescript
function makeArray<T = string>(...args: T[]): T[] {
  return args;
}

console.log(makeArray("a", "b", "c")); // 使用默认类型 string
console.log(makeArray<number>(1, 2, 3)); // 指定类型 number

示例 5: 泛型接口

你还可以定义泛型接口,使接口本身或其成员可以接受类型参数。

typescript
interface Box<T> {
  contents: T;
}

const box: Box<string> = { contents: "hello" };

示例 6: 泛型类

泛型不仅限于函数,你还可以创建泛型类,使类的属性和方法能够处理不同的类型。

typescript
class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

const myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
  return x + y;
};

console.log(myGenericNumber.add(10, 20)); // 输出: 30

类型推断

TypeScript 在大多数情况下可以自动推断出泛型参数的具体类型,而不需要显式指定。

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

// 不需要显式指定 <string>
let output = identity("hello"); // 输出: "hello"

泛型工具类型

TypeScript 提供了一些内置的泛型工具类型,可以帮助简化常见的类型操作:

  • Partial<T>:将 T 中的所有属性变为可选。
  • Readonly<T>:将 T 中的所有属性变为只读。
  • Record<K, T>:构建一个新的对象类型,其中键来自 K,值来自 T
  • Pick<T, K>:从 T 中挑选出由 K 指定的属性。
  • Exclude<T, U>:从 T 中排除所有可以赋值给 U 的类型。
  • Extract<T, U>:从 T 中提取出所有可以赋值给 U 的类型。

应用场景

  • 复用代码:通过泛型,你可以编写适用于多种类型的代码,而不需要为每种类型单独编写实现。
  • 类型安全增强:泛型确保了代码在编译时就能捕获类型错误,提高了程序的健壮性。
  • API 设计:使用泛型可以使 API 更加灵活和强大,让用户可以根据需要选择合适的方法调用。

总结

泛型是 TypeScript 中一个非常重要的特性,它使得代码更加灵活、可复用且类型安全。通过合理使用泛型,你可以编写出更加通用和强大的代码。

Released under the MIT License.