泛型类

泛型类允许我们在类定义中使用类型参数,创建可以处理多种类型的类。泛型类在实现数据结构和工具类时特别有用。

基本语法

在类名后添加 <T> 声明类型参数。

class Box<T> {
  private value: T

  constructor(value: T) {
    this.value = value
  }

  getValue(): T {
    return this.value
  }

  setValue(value: T): void {
    this.value = value
  }
}

const stringBox = new Box<string>("hello")
console.log(stringBox.getValue())

const numberBox = new Box(123)
console.log(numberBox.getValue())

Box<T> 类有一个类型参数 T,实例化时指定具体类型。TypeScript 可以根据构造函数参数推断类型。

泛型属性和方法

类的属性和方法都可以使用类型参数。

class Stack<T> {
  private items: T[] = []

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

  pop(): T | undefined {
    return this.items.pop()
  }

  peek(): T | undefined {
    return this.items[this.items.length - 1]
  }

  size(): number {
    return this.items.length
  }

  isEmpty(): boolean {
    return this.items.length === 0
  }
}

const numberStack = new Stack<number>()
numberStack.push(1)
numberStack.push(2)
numberStack.push(3)

console.log(numberStack.pop())
console.log(numberStack.peek())
console.log(numberStack.size())

Stack<T> 是一个通用的栈数据结构,可以存储任意类型的元素。

多个类型参数

类可以有多个类型参数。

class KeyValuePair<K, V> {
  constructor(
    public key: K,
    public value: V
  ) {}

  toString(): string {
    return `${String(this.key)}: ${String(this.value)}`
  }
}

const pair1 = new KeyValuePair("name", "张三")
const pair2 = new KeyValuePair(1, true)

console.log(pair1.toString())
console.log(pair2.toString())

KeyValuePair<K, V> 类有两个类型参数,分别表示键和值的类型。

泛型类继承

泛型类可以继承其他泛型类。

class Collection<T> {
  protected items: T[] = []

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

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

  size(): number {
    return this.items.length
  }
}

class UniqueCollection<T> extends Collection<T> {
  add(item: T): void {
    if (!this.items.includes(item)) {
      super.add(item)
    }
  }
}

const uniqueNumbers = new UniqueCollection<number>()
uniqueNumbers.add(1)
uniqueNumbers.add(2)
uniqueNumbers.add(1)

console.log(uniqueNumbers.getAll())
console.log(uniqueNumbers.size())

UniqueCollection 继承了 Collection,重写了 add 方法确保元素唯一。

泛型类实现接口

泛型类可以实现泛型接口。

interface Repository<T> {
  findById(id: number): T | undefined
  findAll(): T[]
  save(entity: T): void
}

class MemoryRepository<T extends { id: number }> implements Repository<T> {
  private items: T[] = []

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

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

  save(entity: T): void {
    const index = this.items.findIndex(item => item.id === entity.id)
    if (index >= 0) {
      this.items[index] = entity
    } else {
      this.items.push(entity)
    }
  }
}

interface User {
  id: number
  name: string
}

const userRepo = new MemoryRepository<User>()
userRepo.save({ id: 1, name: "张三" })
userRepo.save({ id: 2, name: "李四" })

console.log(userRepo.findById(1))
console.log(userRepo.findAll())

MemoryRepository 实现了 Repository 接口,T extends { id: number } 约束类型必须有 id 属性。

静态成员与泛型

类的静态成员不能使用类的类型参数。

class Container<T> {
  private static count: number = 0

  constructor(private value: T) {
    Container.count++
  }

  getValue(): T {
    return this.value
  }

  static getCount(): number {
    return Container.count
  }
}

const c1 = new Container("hello")
const c2 = new Container(123)
const c3 = new Container(true)

console.log(Container.getCount())

静态成员属于类本身,不依赖于类型参数。每个实例共享静态成员。

泛型约束

泛型类可以约束类型参数的范围。

interface Comparable {
  compareTo(other: this): number
}

class SortedList<T extends Comparable> {
  private items: T[] = []

  add(item: T): void {
    this.items.push(item)
    this.items.sort((a, b) => a.compareTo(b))
  }

  get(index: number): T | undefined {
    return this.items[index]
  }

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

class Person implements Comparable {
  constructor(public name: string, public age: number) {}

  compareTo(other: Person): number {
    return this.age - other.age
  }
}

const sortedList = new SortedList<Person>()
sortedList.add(new Person("张三", 25))
sortedList.add(new Person("李四", 20))
sortedList.add(new Person("王五", 30))

console.log(sortedList.getAll().map(p => p.name))

SortedList<T extends Comparable> 要求 T 必须实现 Comparable 接口,这样才能进行排序。

实际应用

泛型类在实际开发中常用于实现工具类和数据结构。

class EventEmitter<Events extends Record<string, any>> {
  private handlers: Partial<{ [K in keyof Events]: Array<(data: Events[K]) => void> }> = {}

  on<K extends keyof Events>(event: K, handler: (data: Events[K]) => void): void {
    if (!this.handlers[event]) {
      this.handlers[event] = []
    }
    this.handlers[event]!.push(handler)
  }

  emit<K extends keyof Events>(event: K, data: Events[K]): void {
    const handlers = this.handlers[event]
    if (handlers) {
      handlers.forEach(handler => handler(data))
    }
  }

  off<K extends keyof Events>(event: K, handler: (data: Events[K]) => void): void {
    const handlers = this.handlers[event]
    if (handlers) {
      const index = handlers.indexOf(handler)
      if (index >= 0) {
        handlers.splice(index, 1)
      }
    }
  }
}

interface AppEvents {
  login: { userId: number; name: string }
  logout: { userId: number }
  message: { from: string; content: string }
}

const emitter = new EventEmitter<AppEvents>()

emitter.on("login", (data) => {
  console.log(`用户登录: ${data.name}`)
})

emitter.on("message", (data) => {
  console.log(`收到消息: ${data.from} - ${data.content}`)
})

emitter.emit("login", { userId: 1, name: "张三" })
emitter.emit("message", { from: "李四", content: "你好" })

EventEmitter 是一个类型安全的事件发射器,使用泛型确保事件名称和数据类型的正确性。

小结

泛型类是创建可复用类的重要工具。通过类型参数,类可以处理多种类型的数据。泛型类可以继承其他类、实现接口,并支持类型约束。静态成员不能使用类型参数。在实际开发中,泛型类常用于实现数据结构和工具类。