泛型接口

泛型接口允许我们在接口定义中使用类型参数,创建可复用的类型结构。泛型接口在定义通用的数据结构和 API 响应类型时特别有用。

基本语法

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

interface Container<T> {
  value: T
}

const stringContainer: Container<string> = {
  value: "hello"
}

const numberContainer: Container<number> = {
  value: 123
}

console.log(stringContainer.value)
console.log(numberContainer.value)

Container<T> 接口有一个类型参数 T,使用时指定具体类型。

多个类型参数

接口可以有多个类型参数。

interface Pair<K, V> {
  key: K
  value: V
}

const pair1: Pair<string, number> = {
  key: "age",
  value: 25
}

const pair2: Pair<number, boolean> = {
  key: 1,
  value: true
}

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

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

泛型函数类型接口

接口可以定义泛型函数类型。

interface Transformer<T, R> {
  (input: T): R
}

const stringToNumber: Transformer<string, number> = (input) => {
  return input.length
}

const numberToString: Transformer<number, string> = (input) => {
  return input.toString()
}

console.log(stringToNumber("hello"))
console.log(numberToString(123))

Transformer<T, R> 定义了一个函数类型,接受 T 类型参数,返回 R 类型值。

泛型方法接口

接口的方法可以使用接口的类型参数。

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

interface User {
  id: number
  name: string
  email: string
}

class UserRepository implements Repository<User> {
  private users: User[] = []

  findById(id: number): User | undefined {
    return this.users.find(u => u.id === id)
  }

  findAll(): User[] {
    return [...this.users]
  }

  save(entity: User): void {
    const index = this.users.findIndex(u => u.id === entity.id)
    if (index >= 0) {
      this.users[index] = entity
    } else {
      this.users.push(entity)
    }
  }

  delete(id: number): void {
    this.users = this.users.filter(u => u.id !== id)
  }
}

const userRepo = new UserRepository()
userRepo.save({ id: 1, name: "张三", email: "zhangsan@example.com" })
console.log(userRepo.findById(1))

Repository<T> 定义了一个通用的数据仓库接口,UserRepository 实现了这个接口。

泛型接口继承

泛型接口可以继承其他接口。

interface BaseRepository<T> {
  findById(id: number): T | undefined
  findAll(): T[]
}

interface ExtendedRepository<T> extends BaseRepository<T> {
  save(entity: T): void
  delete(id: number): void
}

interface Product {
  id: number
  name: string
  price: number
}

class ProductRepository implements ExtendedRepository<Product> {
  private products: Product[] = []

  findById(id: number): Product | undefined {
    return this.products.find(p => p.id === id)
  }

  findAll(): Product[] {
    return [...this.products]
  }

  save(entity: Product): void {
    const index = this.products.findIndex(p => p.id === entity.id)
    if (index >= 0) {
      this.products[index] = entity
    } else {
      this.products.push(entity)
    }
  }

  delete(id: number): void {
    this.products = this.products.filter(p => p.id !== id)
  }
}

ExtendedRepository 继承了 BaseRepository,添加了更多方法。

默认类型参数

接口可以为类型参数提供默认值。

interface Response<T = any> {
  code: number
  message: string
  data: T
}

const response1: Response = {
  code: 200,
  message: "success",
  data: { name: "张三" }
}

const response2: Response<string> = {
  code: 200,
  message: "success",
  data: "操作成功"
}

console.log(response1)
console.log(response2)

Response<T = any> 的默认类型是 any,使用时可以省略类型参数。

泛型接口与索引签名

泛型接口可以与索引签名结合使用。

interface Dictionary<T> {
  [key: string]: T
}

const scores: Dictionary<number> = {
  math: 90,
  english: 85,
  chinese: 88
}

const translations: Dictionary<string> = {
  hello: "你好",
  world: "世界"
}

console.log(scores.math)
console.log(translations.hello)

Dictionary<T> 定义了一个键值对结构,值的类型由 T 决定。

实际应用

泛型接口在实际开发中常用于定义 API 响应和配置类型。

interface ApiResponse<T> {
  code: number
  message: string
  data: T
  timestamp: number
}

interface PaginatedResponse<T> extends ApiResponse<T[]> {
  total: number
  page: number
  pageSize: number
}

interface User {
  id: number
  name: string
}

async function fetchUsers(page: number, pageSize: number): Promise<PaginatedResponse<User>> {
  return {
    code: 200,
    message: "success",
    data: [
      { id: 1, name: "张三" },
      { id: 2, name: "李四" }
    ],
    timestamp: Date.now(),
    total: 100,
    page,
    pageSize
  }
}

async function main() {
  const response = await fetchUsers(1, 10)
  console.log(`总数: ${response.total}`)
  console.log(`用户: ${response.data.map(u => u.name).join(", ")}`)
}

main()

泛型接口让 API 响应类型可以复用,同时保持类型安全。

小结

泛型接口是定义可复用类型结构的重要工具。通过类型参数,接口可以适应不同的数据类型。泛型接口可以继承、设置默认类型参数,并与索引签名结合使用。在实际开发中,泛型接口常用于定义通用的数据结构和 API 响应类型。