返回博客列表
语言特性

TypeScript 高级类型技巧

2025-09-15
6 分钟阅读
TypeScript类型系统
TypeScript 高级类型技巧

TypeScript 高级类型技巧

TypeScript 的类型系统是它最强大的特性之一。掌握高级类型技巧不仅能提升代码的类型安全性,还能让开发更加高效。

基础类型回顾

在深入高级类型之前,让我们先回顾一下 TypeScript 的基础类型:

// 基础类型
let name: string = "张三"
let age: number = 25
let isActive: boolean = true

// 数组类型
let numbers: number[] = [1, 2, 3]
let names: Array<string> = ["张三", "李四"]

// 对象类型
interface User {
  id: number
  name: string
  email: string
}

联合类型和交叉类型

联合类型 (Union Types)

联合类型允许一个变量可以是多种类型中的一种:

// 基础联合类型
let id: string | number = "123"
id = 456 // 也有效

// 字面量联合类型
type Status = "pending" | "approved" | "rejected"

function handleStatus(status: Status) {
  switch (status) {
    case "pending":
      return "处理中..."
    case "approved":
      return "已通过"
    case "rejected":
      return "已拒绝"
  }
}

交叉类型 (Intersection Types)

交叉类型将多个类型合并为一个类型:

interface Person {
  name: string
  age: number
}

interface Employee {
  employeeId: string
  department: string
}

// 交叉类型
type EmployeePerson = Person & Employee

const employee: EmployeePerson = {
  name: "张三",
  age: 30,
  employeeId: "E001",
  department: "技术部"
}

泛型 (Generics)

泛型是 TypeScript 中最强大的特性之一,它允许我们创建可重用的组件:

基础泛型

// 基础泛型函数
function identity<T>(arg: T): T {
  return arg
}

const result1 = identity<string>("Hello") // 类型为 string
const result2 = identity<number>(42)      // 类型为 number

// 泛型接口
interface ApiResponse<T> {
  data: T
  status: number
  message: string
}

// 使用泛型接口
const userResponse: ApiResponse<User> = {
  data: { id: 1, name: "张三", email: "zhang@example.com" },
  status: 200,
  message: "Success"
}

泛型约束

// 约束泛型必须有 length 属性
function logLength<T extends { length: number }>(arg: T): T {
  console.log(arg.length)
  return arg
}

logLength("Hello")        // 字符串有 length 属性
logLength([1, 2, 3])      // 数组有 length 属性
// logLength(123)         // 错误:数字没有 length 属性

映射类型 (Mapped Types)

映射类型允许我们基于现有类型创建新类型:

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

// 将所有属性变为可选
type PartialUser = {
  [K in keyof User]?: User[K]
}

// 将所有属性变为只读
type ReadonlyUser = {
  readonly [K in keyof User]: User[K]
}

// 将所有属性变为字符串
type StringUser = {
  [K in keyof User]: string
}

条件类型 (Conditional Types)

条件类型允许我们根据条件选择类型:

// 基础条件类型
type IsString<T> = T extends string ? true : false

type Test1 = IsString<string>  // true
type Test2 = IsString<number>  // false

// 更复杂的条件类型
type NonNullable<T> = T extends null | undefined ? never : T

type Test3 = NonNullable<string | null>  // string
type Test4 = NonNullable<number | undefined>  // number

工具类型 (Utility Types)

TypeScript 提供了许多内置的工具类型:

Partial 和 Required

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

// Partial: 所有属性变为可选
type PartialUser = Partial<User>
// 等同于 { id?: number; name?: string; email?: string; age?: number }

// Required: 所有属性变为必需
type RequiredUser = Required<User>
// 等同于 { id: number; name: string; email: string; age: number }

Pick 和 Omit

interface User {
  id: number
  name: string
  email: string
  password: string
  createdAt: Date
}

// Pick: 选择特定属性
type UserBasicInfo = Pick<User, 'id' | 'name' | 'email'>
// 等同于 { id: number; name: string; email: string }

// Omit: 排除特定属性
type UserWithoutPassword = Omit<User, 'password'>
// 等同于 { id: number; name: string; email: string; createdAt: Date }

模板字面量类型

// 基础模板字面量类型
type EventName<T extends string> = `on${Capitalize<T>}`

type ClickEvent = EventName<'click'>  // 'onClick'
type ChangeEvent = EventName<'change'>  // 'onChange'

// 更复杂的例子
type ApiEndpoint<T extends string> = `/api/${T}`

type UserEndpoint = ApiEndpoint<'users'>  // '/api/users'
type PostEndpoint = ApiEndpoint<'posts'>  // '/api/posts'

实际应用示例

API 响应类型

// 定义 API 响应类型
interface ApiResponse<T> {
  data: T
  success: boolean
  message: string
  timestamp: string
}

// 用户相关 API
interface User {
  id: number
  name: string
  email: string
}

type UserApiResponse = ApiResponse<User>
type UserListApiResponse = ApiResponse<User[]>

// 使用示例
async function fetchUser(id: number): Promise<UserApiResponse> {
  const response = await fetch(`/api/users/${id}`)
  return response.json()
}

表单验证类型

// 表单字段类型
type FormField<T> = {
  value: T
  error?: string
  touched: boolean
}

// 用户表单类型
type UserForm = {
  name: FormField<string>
  email: FormField<string>
  age: FormField<number>
}

// 表单验证函数
function validateForm(form: UserForm): boolean {
  return Object.values(form).every(field => 
    field.value !== undefined && !field.error
  )
}

最佳实践

1. 使用类型别名提高可读性

// 不好的做法
function processData(data: { id: number; name: string; items: { id: number; value: string }[] }) {
  // ...
}

// 好的做法
type Item = {
  id: number
  value: string
}

type Data = {
  id: number
  name: string
  items: Item[]
}

function processData(data: Data) {
  // ...
}

2. 使用泛型提高代码复用性

// 通用的 API 客户端
class ApiClient<T> {
  constructor(private baseUrl: string) {}

  async get<R>(endpoint: string): Promise<ApiResponse<R>> {
    const response = await fetch(`${this.baseUrl}${endpoint}`)
    return response.json()
  }

  async post<R>(endpoint: string, data: T): Promise<ApiResponse<R>> {
    const response = await fetch(`${this.baseUrl}${endpoint}`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    })
    return response.json()
  }
}

// 使用示例
const userApi = new ApiClient<User>('https://api.example.com')
const users = await userApi.get<User[]>('/users')

总结

TypeScript 的高级类型系统为我们提供了强大的工具来构建类型安全的应用程序。通过掌握这些技巧,我们可以:

  • 提高代码的类型安全性
  • 减少运行时错误
  • 改善开发体验
  • 创建更可维护的代码

记住,类型系统的学习是一个渐进的过程,从简单的类型注解开始,逐步掌握更高级的特性。最重要的是在实际项目中不断练习和应用这些概念。