TypeScript 类、泛型的使用实践记录 | 豆包MarsCode AI刷题

55 阅读4分钟

TypeScript 类与泛型的使用实践

在 TypeScript 中,类(Class)和泛型(Generics)是两种非常重要的特性。类支持面向对象编程的核心思想,提供了封装、继承和多态等能力;泛型则通过灵活的类型参数增强了代码的复用性与类型安全性。在项目开发中,这两者常常结合使用,用于解决实际业务中的复杂问题。以下通过实践记录详细说明它们的应用。


TypeScript 类的基本概念与实践

类是 TypeScript 提供的面向对象编程工具,支持属性、方法和构造函数的定义。以下是一个简单的用户管理类的示例:

class User {
  constructor(public name: string, private age: number) {}

  getAge(): number {
    return this.age;
  }

  setAge(age: number): void {
    if (age > 0) {
      this.age = age;
    } else {
      throw new Error("Age must be positive");
    }
  }
}

// 使用示例
const user = new User("Alice", 25);
console.log(user.name); // 输出: Alice
console.log(user.getAge()); // 输出: 25

user.setAge(30);
console.log(user.getAge()); // 输出: 30

在这个示例中,User 类使用了访问修饰符publicprivate)来控制属性的可见性,确保类的内聚性和数据安全性。同时,构造函数使得实例化类对象更加直观。

通过封装数据和操作逻辑,我们可以在项目中对复杂对象进行模块化管理。


泛型的作用与应用

泛型提供了一种方法,使得函数、类或接口可以接收多个不同类型,同时保持类型安全。以下是一个通用的泛型函数:

function identity<T>(value: T): T {
  return value;
}

const numberValue = identity<number>(123); // 类型为 number
const stringValue = identity<string>("Hello"); // 类型为 string

console.log(numberValue); // 输出: 123
console.log(stringValue); // 输出: Hello

这里的 T 是一个类型变量,可以由调用者根据实际需求指定。泛型使代码更加灵活,减少了重复工作,也提升了类型检查的能力。


类与泛型的结合

在实际项目中,类与泛型的结合非常普遍。下面以一个缓存管理器的实现为例,说明泛型在类中的应用:

class Cache<T> {
  private store: Map<string, T> = new Map();

  set(key: string, value: T): void {
    this.store.set(key, value);
  }

  get(key: string): T | undefined {
    return this.store.get(key);
  }

  clear(): void {
    this.store.clear();
  }
}

// 使用缓存管理器
const stringCache = new Cache<string>();
stringCache.set("username", "Alice");
console.log(stringCache.get("username")); // 输出: Alice

const numberCache = new Cache<number>();
numberCache.set("age", 25);
console.log(numberCache.get("age")); // 输出: 25

通过引入泛型,Cache 类能够支持任意数据类型,极大提高了代码的复用性。在项目中,我们可以用类似的方式实现通用工具类,例如数据队列、任务调度器等。


泛型约束的使用

有时,我们需要对泛型的类型范围进行约束。TypeScript 提供了 extends 关键字,可以确保泛型参数满足某些条件。例如,实现一个带有 ID 属性的仓库管理类:

interface HasId {
  id: number;
}

class Repository<T extends HasId> {
  private items: T[] = [];

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

  findById(id: number): T | undefined {
    return this.items.find((item) => item.id === id);
  }
}

// 使用示例
const userRepo = new Repository<{ id: number; name: string }>();
userRepo.add({ id: 1, name: "Alice" });
userRepo.add({ id: 2, name: "Bob" });

console.log(userRepo.findById(1)); // 输出: { id: 1, name: "Alice" }

在这个例子中,T 被限制为必须具有 id 属性。这种约束确保了类型安全,同时也能引导开发者更规范地设计数据结构。


在实际项目中的应用场景

以下是类和泛型在实际开发中的一些应用场景:

  1. API 响应的封装 在前端开发中,泛型经常被用于封装通用的接口返回结构。例如:

    class ApiResponse<T> {
      constructor(public data: T, public success: boolean, public message: string) {}
    }
    
    const userResponse = new ApiResponse<{ name: string; age: number }>(
      { name: "Alice", age: 25 },
      true,
      "Request successful"
    );
    
    console.log(userResponse.data.name); // 输出: Alice
    

    通过泛型参数,ApiResponse 类可以轻松适配不同的数据模型,避免重复定义类似结构。

  2. 动态表单生成 使用泛型结合类,可以实现动态表单的生成与管理。例如,一个通用的表单管理类可以定义为:

    class Form<T> {
      constructor(public fields: T) {}
    
      validate(): boolean {
        // 实现验证逻辑
        return true;
      }
    }
    
    const userForm = new Form<{ name: string; age: number }>({
      name: "Alice",
      age: 25,
    });
    
    console.log(userForm.fields.name); // 输出: Alice
    
  3. 复杂数据的分页处理 在后台管理系统中,分页处理是常见需求。利用泛型可以实现通用的分页逻辑:

    class Paginator<T> {
      constructor(public items: T[], public pageSize: number) {}
    
      getPage(page: number): T[] {
        const start = (page - 1) * this.pageSize;
        return this.items.slice(start, start + this.pageSize);
      }
    }
    
    const paginator = new Paginator<string>(["Alice", "Bob", "Charlie"], 2);
    console.log(paginator.getPage(1)); // 输出: ["Alice", "Bob"]
    

总结

通过结合使用类和泛型,TypeScript 为开发者提供了强大的工具,既能够实现复杂的逻辑封装,也可以大幅提高代码的灵活性与复用性。在实际开发中,掌握类的封装特性和泛型的灵活运用,并根据业务场景合理设计数据模型,是提升开发效率和代码质量的关键。