Typescript 泛型的定义和使用范围


在 TypeScript 中,你可以在定义类型时使用泛型。泛型允许你创建可重用的类型定义,这些类型定义可以根据传入的类型参数进行调整。这使得类型定义更加灵活和强大。


泛型类型定义

1. 基本语法

你可以使用 <T>(或其他任何标识符)来定义泛型类型参数。例如:

type Box<T> = {
  value: T
}

const boxNumber: Box<number> = { value: 42 }
const boxString: Box<string> = { value: 'hello' }

在这个例子中,Box<T> 是一个泛型类型,T 是类型参数。你可以根据需要传入不同的类型参数来创建不同类型的 Box

2. 多个类型参数

你可以在一个类型定义中使用多个类型参数:

type Pair<T, U> = {
  first: T
  second: U
}

const pair1: Pair<number, string> = { first: 42, second: 'hello' }
const pair2: Pair<string, boolean> = { first: 'world', second: true }

3. 泛型约束

你可以使用 extends 关键字来约束泛型参数,确保它们满足某些条件。例如,你可以约束泛型参数必须具有某个属性:

type HasId<T extends { id: number }> = T & { name: string }

const obj1: HasId<{ id: number; age: number }> = {
  id: 1,
  age: 30,
  name: 'Alice',
}
// const obj2: HasId<{ age: number }> = { age: 30, name: 'Bob' }; // 错误:缺少 id 属性

在这个例子中,HasId<T> 要求 T 必须包含 id 属性。

4. 默认类型参数

你可以为泛型参数提供默认类型,这样在没有显式指定类型参数时会使用默认类型:

type Container<T = string> = {
  value: T
}

const container1: Container = { value: 'default' } // 使用默认类型 string
const container2: Container<number> = { value: 42 } // 显式指定类型 number

泛型函数

你也可以在函数中使用泛型,使得函数可以处理多种类型的参数:

function identity<T>(arg: T): T {
  return arg
}

const num = identity<number>(42)
const str = identity<string>('hello')

泛型接口

你还可以在接口中使用泛型:

interface Box<T> {
  value: T
}

const boxNumber: Box<number> = { value: 42 }
const boxString: Box<string> = { value: 'hello' }

泛型类

在类中使用泛型也很常见,特别是在实现泛型容器类时:

class Box<T> {
  value: T

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

  getValue(): T {
    return this.value
  }
}

const boxNumber = new Box<number>(42)
const boxString = new Box<string>('hello')

console.log(boxNumber.getValue()) // 42
console.log(boxString.getValue()) // hello

总结

通过使用泛型,你可以创建更加灵活和可重用的类型定义。泛型允许你在定义类型、函数、接口和类时使用类型参数,从而根据不同的需求调整类型。