类型别名

类型别名给类型起一个新名字,可以用于原始类型、联合类型、交叉类型、对象类型等。类型别名让复杂类型更易读,提高代码的可维护性。

基本语法

使用 type 关键字定义类型别名。

type Name = string
type Age = number

const name: Name = "张三"
const age: Age = 25

console.log(name, age)

NameAge 分别是 stringnumber 的别名。

对象类型别名

类型别名常用于定义对象类型。

type User = {
  id: number
  name: string
  email: string
}

const user: User = {
  id: 1,
  name: "张三",
  email: "zhangsan@example.com"
}

console.log(user.name)

User 是一个对象类型的别名,描述了用户的数据结构。

联合类型别名

类型别名可以用于联合类型。

type ID = string | number
type Status = "active" | "inactive" | "pending"

function processId(id: ID): void {
  console.log(`处理 ID: ${id}`)
}

function updateStatus(status: Status): void {
  console.log(`更新状态: ${status}`)
}

processId("user-001")
processId(123)

updateStatus("active")
updateStatus("pending")

联合类型别名让类型定义更加简洁和可复用。

交叉类型别名

类型别名可以用于交叉类型。

type Name = {
  name: string
}

type Age = {
  age: number
}

type Person = Name & Age

const person: Person = {
  name: "张三",
  age: 25
}

console.log(person)

交叉类型别名合并多个类型的特性。

函数类型别名

类型别名可以定义函数类型。

type Handler = (event: Event) => void
type Compare<T> = (a: T, b: T) => number

const clickHandler: Handler = (event) => {
  console.log("点击事件", event.type)
}

const numberCompare: Compare<number> = (a, b) => a - b

console.log(numberCompare(3, 1))

函数类型别名让回调函数和比较函数的类型定义更加清晰。

泛型类型别名

类型别名可以使用泛型。

type Container<T> = {
  value: T
}

type ApiResponse<T> = {
  code: number
  message: string
  data: T
}

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

const userResponse: ApiResponse<{ id: number; name: string }> = {
  code: 200,
  message: "success",
  data: { id: 1, name: "张三" }
}

泛型类型别名提供了更灵活的类型定义。

类型别名与接口的区别

类型别名和接口有一些区别。

type Point = {
  x: number
  y: number
}

interface IPoint {
  x: number
  y: number
}

const typePoint: Point = { x: 1, y: 2 }
const interfacePoint: IPoint = { x: 1, y: 2 }

主要区别:

  • 接口可以被扩展和实现,类型别名不能
  • 类型别名可以表示联合类型、交叉类型等,接口只能表示对象类型
  • 接口可以声明合并,类型别名不能
  • 类型别名可以用于原始类型,接口不能

类型别名扩展

类型别名可以通过交叉类型扩展。

type Base = {
  id: number
}

type User = Base & {
  name: string
  email: string
}

const user: User = {
  id: 1,
  name: "张三",
  email: "zhangsan@example.com"
}

类型别名使用 & 扩展,接口使用 extends 扩展。

递归类型别名

类型别名可以递归定义。

type Json = string | number | boolean | null | Json[] | { [key: string]: Json }

const data: Json = {
  name: "张三",
  age: 25,
  hobbies: ["阅读", "运动"],
  address: {
    city: "北京"
  }
}

console.log(data)

Json 类型递归定义了 JSON 数据的结构。

实际应用

类型别名在实际开发中常用于定义通用类型。

type Result<T, E = Error> = {
  success: true
  value: T
} | {
  success: false
  error: E
}

function divide(a: number, b: number): Result<number> {
  if (b === 0) {
    return {
      success: false,
      error: new Error("除数不能为零")
    }
  }
  return {
    success: true,
    value: a / b
  }
}

const result1 = divide(10, 2)
const result2 = divide(10, 0)

if (result1.success) {
  console.log(`结果: ${result1.value}`)
}

if (!result2.success) {
  console.log(`错误: ${result2.error.message}`)
}

Result 类型别名定义了一个通用的结果类型,可以表示成功或失败。

小结

类型别名使用 type 关键字给类型起一个新名字。可以用于原始类型、对象类型、联合类型、交叉类型、函数类型等。泛型类型别名提供了更灵活的类型定义。类型别名与接口有各自的特点和适用场景。合理使用类型别名可以提高代码的可读性和可维护性。