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

01 TypeScript简介

​ TypeScript是一种由微软开发的编程语言,它是JavaScript的超集,可以编译为纯JavaScript代码。TypeScript添加了静态类型、类、接口和模块等功能,使得开发者可以更加规范和可靠地编写JavaScript代码。它还提供了更好的代码提示和自动补全功能,以及更强大的工具支持。TypeScript可以在任何支持JavaScript的地方运行,并且可以与现有的JavaScript库和框架无缝集成。

02 TypeScript类的基本使用

  • 类的定义和声明:
typescript 复制代码
typescript
复制代码
class Person {
  private name: string;
  constructor(name: string) {
    this.name = name;
  }
  sayHello() {
    console.log(`Hello, my name is ${this.name}.`);
  }
}

在此案例中,定义了一个名为Person的类。它有一个私有属性name和一个构造函数,构造函数接受一个参数name并将其赋值给属性name。类中还有一个名为sayHello的方法,它会在控制台输出一句问候语,包含了属性name的值。

  • 属性和方法的定义和访问修饰符:
typescript 复制代码
typescript
复制代码
class Person {
  private name: string;
  protected age: number;
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}

在此引入了访问修饰符。私有属性name只能在类内部访问,而受保护属性age可以在类内部和子类中访问。构造函数接受两个参数name和age,将它们分别赋值给对应的属性。

  • 类的继承和多态性:
typescript 复制代码
typescript
复制代码
class Student extends Person {
  private grade: number;
  constructor(name: string, age: number, grade: number) {
    super(name, age);
    this.grade = grade;
  }
  sayHello() {
    console.log(`Hello, my name is ${this.name}, I'm ${this.age} years old, and I'm in grade ${this.grade}.`);
  }
}
  • 抽象类和接口的使用:
typescript 复制代码
typescript
复制代码
abstract class Shape {
  abstract getArea(): number;
}

interface Printable {
  print(): void;
}

class Circle extends Shape implements Printable {
  private radius: number;
  constructor(radius: number) {
    super();
    this.radius = radius;
  }
  getArea() {
    return Math.PI * this.radius ** 2;
  }
  print() {
    console.log(`The area of the circle is ${this.getArea()}.`);
  }
}

在抽象类Shape定义了一个抽象方法getArea,它没有具体的实现,只是用来约束子类必须实现该方法。接口Printable定义了一个方法print,任何实现该接口的类都必须实现print方法。Circle类继承了Shape抽象类,并实现了Printable接口。它有一个私有属性radius,并实现了getArea和print方法。

03 TypeScript泛型的基本概念

  • 泛型的定义和声明:
sql 复制代码
typescript
复制代码
function identity<T>(arg: T): T {
  return arg;
}
let result = identity<string>("Hello TypeScript");
console.log(result);

期望输出:Hello TypeScript

  • 泛型类、泛型函数和泛型接口的使用:
typescript 复制代码
typescript
复制代码
class Box<T> {
  private value: T;
  constructor(value: T) {
    this.value = value;
  }
  getValue(): T {
    return this.value;
  }
}
let box = new Box<number>(10);
console.log(box.getValue()); // Output: 10

function printArray<T>(arr: T[]): void {
  for (let item of arr) {
    console.log(item);
  }
}
printArray<number>([1, 2, 3, 4, 5]);

interface Pair<T, U> {
  first: T;
  second: U;
}
let pair: Pair<number, string> = { first: 1, second: "two" };

04 泛型的使用场景与实践

  • 在容器类中使用泛型,如数组、集合等:
ini 复制代码
typescript
复制代码
function reverse<T>(arr: T[]): T[] {
  return arr.reverse();
}
let reversedArray = reverse<number>([1, 2, 3, 4, 5]);
console.log(reversedArray);

期望输出:[5, 4, 3, 2, 1]

reverse函数接受一个泛型参数arr,它是一个数组,并将数组反转后返回。在调用reverse函数时,我们显式地指定了泛型参数为number类型的数组。

  • 在函数中使用泛型,增加函数的通用性
ini 复制代码
typescript
复制代码
function mergeArrays<T>(arr1: T[], arr2: T[]): T[] {
  return [...arr1, ...arr2];
}
let mergedArray = mergeArrays<number>([1, 2, 3], [4, 5, 6]);
console.log(mergedArray);

期望输出:[1, 2, 3, 4, 5, 6]

  • 在接口中使用泛型,使接口更加灵活
scss 复制代码
typescript
复制代码
interface Repository<T> {
  getById(id: number): T;
  getAll(): T[];
  save(item: T): void;
  update(item: T): void;
  delete(id: number): void;
}
  • 在类中使用泛型,提高代码的复用性和可扩展性:
arduino 复制代码
typescript
复制代码
class Stack<T> {
  private items: T[] = [];
  push(item: T): void {
    this.items.push(item);
  }
  pop(): T | undefined {
    return this.items.pop();
  }
}
let stack = new Stack<number>();
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.pop()); 

期望输出:3

05 使用类型约束增加代码的灵活性和安全性

  • 使用泛型约束,限制泛型的类型范围:
typescript 复制代码
typescript
复制代码
interface Lengthwise {
  length: number;
}

function printLength<T extends Lengthwise>(arg: T): void {
  console.log(arg.length);
}
printLength("Hello"); // Output: 5
printLength([1, 2, 3, 4, 5]); // Output: 5
  • 使用关键字"extends"进行类型约束:
ini 复制代码
typescript
复制代码
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}
let person = { name: "Alice", age: 30 };
let name = getProperty(person, "name");
console.log(name);

期望输出:Alice

  • 通过类型约束避免运行时错误和类型错误:
typescript 复制代码
typescript
复制代码
function safeParseJson<T>(jsonString: string): T | null {
  try {
    return JSON.parse(jsonString) as T;
  } catch (e) {
    console.error("Invalid JSON string:", e);
    return null;
  }
}
let parsedData = safeParseJson<{ name: string }>('{"name": "Alice"}');
if (parsedData) {
  console.log(parsedData.name);
}

期望输出:Alice

此代码中safeParseJson函数接受一个泛型参数T和一个字符串jsonString,它尝试将jsonString解析为类型T,并返回解析后的结果。在try块中,我们使用as操作符将解析结果断言为类型T。如果解析成功,函数返回解析结果;否则,函数捕获错误并返回null。在调用safeParseJson函数时,在此显式地指定了泛型参数为一个包含name属性的对象类型,所以函数能够正确解析并返回相应的数据。

06 总结

​ 通过TypeScript的类和泛型特性,可以在代码中实现更高的灵活性和安全性。类的继承、多态性、抽象类和接口使得代码更加模块化和可复用,而泛型的使用则增加了代码的通用性和可扩展性。通过使用类型约束,我们可以避免运行时错误和类型错误,提高代码的可维护性。因此,在TypeScript中合理地使用类和泛型,并加以类型约束,有助于提高代码的质量和开发效率。

相关推荐
夭要7夜宵4 天前
Go 垃圾回收 | 豆包MarsCode AI刷题
青训营笔记
末班车4224 天前
前端框架中的设计模式 | 豆包MarsCode AI刷题
青训营笔记
VanceLLF5 天前
神奇数字组合 | 豆包MarsCode AI刷题
青训营笔记
lann5 天前
Go 程序的优化 | 豆包MarsCode AI刷题
青训营笔记
用户52281271049785 天前
性能优化与调试技巧 | 豆包MarsCode AI刷题
青训营笔记
千慌百风定乾坤7 天前
Go 语言入门指南:基础语法和常用特性解析(下) | 豆包MarsCode AI刷题
青训营笔记
FOFO7 天前
青训营笔记 | HTML语义化的案例分析: 粗略地手绘分析juejin.cn首页 | 豆包MarsCode AI 刷题
青训营笔记
滑滑滑9 天前
后端实践-优化一个已有的 Go 程序提高其性能 | 豆包MarsCode AI刷题
青训营笔记
柠檬柠檬9 天前
Go 语言入门指南:基础语法和常用特性解析 | 豆包MarsCode AI刷题
青训营笔记
用户967136399659 天前
计算最小步长丨豆包MarsCodeAI刷题
青训营笔记