探讨TypeScript中的泛型的使用方法和场景|青训营

1.泛型介绍

泛型的主要作用是增强代码的可重用性、类型安全性和灵活性。通过使用泛型,我们可以编写更通用的代码,能够适应多种不同的数据类型,并且在编译阶段进行类型检查,减少潜在的运行时错误。在TS中,泛型可以应用于函数、类和接口。

2.泛型使用场景

2.1 数据结构的抽象化

使用泛型可以将数据结构中的类型信息参数化,使得数据结构在定义时不需要指定具体的数据类型,而是在使用时根据实际情况来确定。这样就可以编写通用的数据结构和算法,而不需要为每种特定类型都编写重复的代码,提高了代码的可重用性和灵活性。比如下面使用泛型来定义一个通用的数据结构,这样我们就可以利用其创建存储数字的栈和存储字符串的栈。

ts 复制代码
class Stack<T> {
  private items: T[] = [];
​
  push(item: T) {
    this.items.push(item);
  }
​
  pop() {
    return this.items.pop();
  }
}
​
// 创建一个存储数字的栈
const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);
console.log(numberStack.pop()); // 输出:3
​
// 创建一个存储字符串的栈
const stringStack = new Stack<string>();
stringStack.push('Hello');
stringStack.push('World');
console.log(stringStack.pop()); // 输出:'World'
​

2.2 函数的灵活参数类型

使用泛型可以让函数适用于不同的参数类型,而不需要针对每种类型编写重复的代码,同时在编译阶段对函数的参数类型进行检查,有利于发现潜在类型问题。

ts 复制代码
function reverse<T>(items: T[]): T[] {
  return items.reverse();
}
​
const numbers = [1, 2, 3];
const reversedNumbers = reverse(numbers);
console.log(reversedNumbers); // 输出:[3, 2, 1]
​
const strings = ['a', 'b', 'c'];
const reversedStrings = reverse(strings);
console.log(reversedStrings); // 输出:['c', 'b', 'a']
​

2.3 接口泛型定义

接口泛型允许我们在接口的定义中使用参数化类型,以便在实现接口时动态地指定具体的类型,同时通过使用泛型定义接口,可以创建可扩展的抽象定义,比如与继承、联合类型等结合使用,从而实现更复杂的数据结构和功能。下面就是泛型接口和联合类型相结合,计算这两种图形面积和的例子。

ts 复制代码
interface Shape {
  getArea(): number;
}
​
interface Square<T> extends Shape {
  sideLength: T;
}
​
interface Circle<T> extends Shape {
  radius: T;
}
​
// 正方形和圆形的联合类型
type ShapeType = Square<number> | Circle<number>;
​
// 计算总面积
function calculateTotalArea(shapes: ShapeType[]): number {
  let totalArea = 0;
  for (let shape of shapes) {
    totalArea += shape.getArea();
  }
  return totalArea;
}
​
// 计算正方形面积
class SquareImpl implements Square<number> {
  constructor(public sideLength: number) {}
  getArea(): number {
    return this.sideLength * this.sideLength;
  }
}
​
// 计算圆形面积
class CircleImpl implements Circle<number> {
  constructor(public radius: number) {}
  getArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}
​
const square = new SquareImpl(5);
const circle = new CircleImpl(3);
​
const totalArea = calculateTotalArea([square, circle]);
console.log(totalArea);  // 输出:84.53981633974483
​

2.4 泛型约束

通过使用泛型约束,可以对泛型类型参数进行类型约束,以使其满足特定的属性或行为要求,能够极大的增强类型的安全性。比如下面的泛型约束就是参入的参数必须有length属性且类型必须是数字。

ts 复制代码
interface Lengthy {
  length: number;
}
​
function printLength<T extends Lengthy>(obj: T): void {
  console.log(obj.length);
}
​
printLength('Hello');  // 输出:5
printLength([1, 2, 3]);  // 输出:3
​

3 总结

泛型通过类型约束为代码增加了灵活性和安全性。利用泛型可以在定义函数、类或接口时使用类型参数作为占位符,使得代码可以适用于不同的数据类型。通过给泛型添加类型约束可以限定泛型参数的类型范围,确保代码只能被特定类型的数据调用,从而避免潜在的类型错误。这种灵活性使得我们能够编写更通用、可重用的代码,同时在编译阶段就能发现并修复类型相关的错误,提高了代码的安全性和可维护性。通过使用泛型,我们能够更好地应对不同类型数据的需求,同时减少了重复代码的编写,增加了代码的灵活性和可读性。

相关推荐
淇逢春4 天前
可被K整除的子数组问题 | 豆包MarsCode AI 刷题
青训营笔记
静水流深3971 个月前
03 模型IO| 豆包MarsCode AI刷题
青训营笔记
用户247841860021 个月前
第七次算法笔记 | 豆包MarsCode AI刷题
青训营笔记
幻61 个月前
小S的倒排索引 | 豆包MarsCode AI刷题
青训营笔记
用户826014428302 个月前
469. 环形数组最大子数组和问题
青训营笔记
用户605721920982 个月前
奇妙货币交易问题 | 豆包MarsCode AI刷题
青训营笔记
我明天再来学Web渗透2 个月前
“抖音互联网架构分析及高可用系统构建思考”(方向三)| 豆包MarsCode AI刷题
青训营笔记
用户302133066202 个月前
第三次刷题 | 豆包MarsCode AI刷题
青训营笔记
用户9105973027702 个月前
CSS详解| 豆包MarsCode AI刷题
青训营笔记
huyck2 个月前
伴学笔记1|豆包MarsCode AI 刷题
青训营笔记