返回

TypeScript中的泛型(第二部分:泛型约束)

前端

泛型约束

泛型约束可以用于指定类型参数必须满足的条件。条件可以是接口、类或另一个类型。例如,以下代码定义了一个泛型函数,该函数接受一个类型参数T,并要求T必须实现Comparable接口:

interface Comparable<T> {
  compareTo(other: T): number;
}

function compare<T extends Comparable<T>>(a: T, b: T): number {
  return a.compareTo(b);
}

这个函数只能用于实现了Comparable接口的类型。这意味着您可以确信,在调用函数之前,ab都实现了compareTo方法。

接口

接口是一种定义类型的方法。接口可以包含属性、方法和事件。例如,以下代码定义了一个Comparable接口,其中包含一个compareTo方法:

interface Comparable<T> {
  compareTo(other: T): number;
}

compareTo方法接受一个类型为T的参数,并返回一个数字。这个数字表示当前对象与参数对象的比较结果。如果当前对象小于参数对象,则返回一个负数;如果当前对象等于参数对象,则返回0;如果当前对象大于参数对象,则返回一个正数。

类型注解

类型注解是TypeScript中用于指定变量或表达式的类型的一种语法。例如,以下代码为变量a指定了类型number

let a: number = 10;

类型注解有助于确保变量只存储预期类型的值。这有助于防止在运行时出现错误。

错误处理

泛型约束和接口可以帮助您在编译时捕获错误。例如,以下代码会产生一个编译时错误,因为a没有实现Comparable接口:

let a: number = 10;
let b: number = 20;
compare(a, b); // Error: Argument of type 'number' is not assignable to parameter of type 'Comparable<number>'

这个错误告诉您,compare函数只能用于实现了Comparable接口的类型。这意味着您无法将一个数字与另一个数字进行比较。

代码复用

泛型约束和接口可以帮助您重用代码。例如,以下代码定义了一个名为max的泛型函数,该函数返回两个值中较大的那个:

function max<T extends Comparable<T>>(a: T, b: T): T {
  if (a.compareTo(b) > 0) {
    return a;
  } else {
    return b;
  }
}

这个函数可以用于任何实现了Comparable接口的类型。这意味着您可以将它用于数字、字符串、日期等。

可读性

泛型约束和接口可以帮助您提高代码的可读性。例如,以下代码定义了一个名为Person的类,该类具有一个name属性和一个age属性:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

如果您想创建一个包含Person对象的数组,可以使用以下代码:

let people: Person[] = [];

这个代码告诉编译器,people数组只能包含Person对象。这有助于防止您在数组中意外地存储其他类型的对象。

代码维护

泛型约束和接口可以帮助您维护代码。例如,如果您想更改Person类的定义,可以使用以下代码:

class Person {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }
}

您只需要在类定义中添加一个greet方法。您不需要更改任何其他代码。这意味着您可以轻松地向类添加新功能,而无需担心破坏其他代码。

结论

泛型约束和接口是TypeScript中用于编写更健壮、更可读、更易维护的代码的两种强大工具。如果您想编写高质量的TypeScript代码,那么您应该熟悉这些概念。