TypeScript 类、泛型的使用实践记录 | 青训营

34 阅读4分钟

本篇为实践笔记,TypeScript 类、泛型的使用实践记录:探讨TypeScript中的泛型的使用方法和场景。

泛型是什么

泛型是一种编程概念,它允许在代码中使用类型参数来处理多种类型的数据,从而增加代码的灵活性和可重用性。泛型可以应用于函数、类、接口等代码结构中。

泛型的主要目的是为了在编译时期提供类型安全性,并在使用时提供更好的代码重用。通过使用泛型,我们可以编写通用的代码,而不需要为每种特定类型单独编写相似的代码。

总而言之,泛型可以应用于各种场景,使代码更具通用性、可扩展性和类型安全性。它允许我们编写一次代码,然后在多种情况下重复使用,减少了冗余代码的编写量。通过合理地应用泛型,我们可以提高代码的可读性、维护性和可测试性。

典型场景

以下是一些典型的泛型使用场景:

  1. 容器类:泛型可以用于创建容器类(如数组、集合、队列等),以容纳不同类型的元素。这样一来,我们可以在容器中存储和操作多种类型的数据,提高代码的灵活性。

  2. 算法函数:泛型可以用于编写算法函数,使其适用于不同类型的数据。例如,排序函数可以使用泛型来接受不同类型的数组作为输入,并返回排序后的结果。

    例如——

    function sortArray<T>(array: T[]): T[] {
      return array.sort();
    }
    
    // 使用示例
    const numbers = [5, 2, 8, 1, 9];
    const sortedNumbers = sortArray(numbers);
    console.log(sortedNumbers); // 输出: [1, 2, 5, 8, 9]
    
    const strings = ["apple", "banana", "cherry", "date"];
    const sortedStrings = sortArray(strings);
    console.log(sortedStrings); // 输出: ["apple", "banana", "cherry", "date"]
    
  3. 数据结构:泛型可以应用于自定义的数据结构,如栈、链表、树等。通过使用泛型,我们可以创建通用的数据结构,以存储和操作各种类型的数据。

    例如——用泛型实现栈

    class Stack<T> {
      private elements: T[] = [];
    
      push(item: T) {
        this.elements.push(item);
      }
    
      pop(): T | undefined {
        return this.elements.pop();
      }
    }
    
    // 使用示例
    const stringStack = new Stack<string>();
    stringStack.push("A");
    stringStack.push("B");
    console.log(stringStack.pop()); // 输出: B
    
    const numberStack = new Stack<number>();
    numberStack.push(1);
    numberStack.push(2);
    console.log(numberStack.pop()); // 输出: 2
    
  4. 接口和抽象类:泛型可以用于定义接口和抽象类,使它们能够适应不同类型的实现。这样,我们可以编写更灵活和可重用的代码,同时保持类型的一致性。

  5. 异步操作:泛型可以在异步操作中使用,以处理异步返回的不同类型的数据。例如,Promise对象可以使用泛型来指定异步操作的返回值类型。

实践运用——购物车

假设我们正在构建一个电子商务平台,其中有多种商品类型,如电子产品、家具、服装等。我们可以使用泛型来创建一个通用的购物车类,该类可以处理各种类型的商品。

class ShoppingCart<T> {
  private items: T[] = [];

  addItem(item: T) {
    this.items.push(item);
  }

  removeItem(item: T) {
    const index = this.items.indexOf(item);
    if (index > -1) {
      this.items.splice(index, 1);
    }
  }

  getItems(): T[] {
    return this.items;
  }

  getTotalItemsCount(): number {
    return this.items.length;
  }

  getTotalPrice(calculatePrice: (item: T) => number): number {
    let totalPrice = 0;
    for (const item of this.items) {
      totalPrice += calculatePrice(item);
    }
    return totalPrice;
  }

  clearCart() {
    this.items = [];
  }
}

// 使用示例
class Product {
  constructor(public name: string, public price: number) {}
}

const electronicCart = new ShoppingCart<Product>();
electronicCart.addItem(new Product("Laptop", 2000));
electronicCart.addItem(new Product("Mobile Phone", 1000));

const furnitureCart = new ShoppingCart<Product>();
furnitureCart.addItem(new Product("Sofa", 500));
furnitureCart.addItem(new Product("Table", 300));

console.log(electronicCart.getItems()); // 输出: [Product { name: "Laptop", price: 2000 }, Product { name: "Mobile Phone", price: 1000 }]
console.log(furnitureCart.getItems()); // 输出: [Product { name: "Sofa", price: 500 }, Product { name: "Table", price: 300 }]

console.log(electronicCart.getTotalItemsCount()); // 输出: 2
console.log(furnitureCart.getTotalItemsCount()); // 输出: 2

const calculatePrice = (item: Product) => item.price;
console.log(electronicCart.getTotalPrice(calculatePrice)); // 输出: 3000
console.log(furnitureCart.getTotalPrice(calculatePrice)); // 输出: 800

electronicCart.removeItem(new Product("Laptop", 2000));
console.log(electronicCart.getItems()); // 输出: [Product { name: "Mobile Phone", price: 1000 }]

electronicCart.clearCart();
console.log(electronicCart.getItems()); // 输出: []

这段代码实现了一个泛型类 ShoppingCart<T>,其中 <T> 表示要存储的物品的类型。该类具有以下方法和功能:

  • addItem(item: T):向购物车中添加物品。
  • removeItem(item: T):从购物车中移除指定的物品。
  • getItems(): T[]:获取购物车中所有物品的列表。
  • getTotalItemsCount(): number:获取购物车中物品的总数量。
  • getTotalPrice(calculatePrice: (item: T) => number): number:根据每个物品的价格计算购物车中物品的总价格。calculatePrice 是一个函数,它接受一个物品作为参数并返回其价格。
  • clearCart():清空购物车,将所有物品移除。

在这个例子中,我们可以在实例化购物车对象时指定不同的商品类型。我们可以向购物车添加商品并从中移除商品,并通过 getItems() 方法获取购物车中的所有商品。对于每种类型的购物车,我们可以确保只添加和获取该类型的商品,从而提高了代码的类型安全性。

这个例子展示了如何使用泛型来处理不同类型的数据,并且使代码具有通用性和可扩展性。无论是电子产品购物车、家具购物车还是其他类型的购物车,我们都可以使用相同的 ShoppingCart<T> 类来管理商品。这样,我们可以编写更灵活和可重用的代码,同时保持类型的一致性。