本篇为实践笔记,TypeScript 类、泛型的使用实践记录:探讨TypeScript中的泛型的使用方法和场景。
泛型是什么
泛型是一种编程概念,它允许在代码中使用类型参数来处理多种类型的数据,从而增加代码的灵活性和可重用性。泛型可以应用于函数、类、接口等代码结构中。
泛型的主要目的是为了在编译时期提供类型安全性,并在使用时提供更好的代码重用。通过使用泛型,我们可以编写通用的代码,而不需要为每种特定类型单独编写相似的代码。
总而言之,泛型可以应用于各种场景,使代码更具通用性、可扩展性和类型安全性。它允许我们编写一次代码,然后在多种情况下重复使用,减少了冗余代码的编写量。通过合理地应用泛型,我们可以提高代码的可读性、维护性和可测试性。
典型场景
以下是一些典型的泛型使用场景:
-
容器类:泛型可以用于创建容器类(如数组、集合、队列等),以容纳不同类型的元素。这样一来,我们可以在容器中存储和操作多种类型的数据,提高代码的灵活性。
-
算法函数:泛型可以用于编写算法函数,使其适用于不同类型的数据。例如,排序函数可以使用泛型来接受不同类型的数组作为输入,并返回排序后的结果。
例如——
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"]
-
数据结构:泛型可以应用于自定义的数据结构,如栈、链表、树等。通过使用泛型,我们可以创建通用的数据结构,以存储和操作各种类型的数据。
例如——用泛型实现栈
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
-
接口和抽象类:泛型可以用于定义接口和抽象类,使它们能够适应不同类型的实现。这样,我们可以编写更灵活和可重用的代码,同时保持类型的一致性。
-
异步操作:泛型可以在异步操作中使用,以处理异步返回的不同类型的数据。例如,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>
类来管理商品。这样,我们可以编写更灵活和可重用的代码,同时保持类型的一致性。