Skip to content

类型别名

概述

类型别名(Type Alias)是 TypeScript 中为类型创建新名称的方式。通过 type 关键字,我们可以为任何类型(包括基础类型、联合类型、交叉类型、函数类型等)创建一个别名,使代码更加清晰、可读和可维护。类型别名提供了比接口更灵活的类型定义方式,特别适合定义联合类型、交叉类型和复杂的类型组合。

基本语法

类型别名使用 type 关键字定义,后跟别名名称、等号和类型定义:

typescript
// 基本语法
type AliasName = Type;

// 示例:为字符串类型创建别名
type UserName = string;
type UserAge = number;

// 使用类型别名
const name: UserName = "John Doe";
const age: UserAge = 30;

基本用法

为对象类型创建别名

类型别名最常见的用法是为对象类型创建别名:

typescript
// 使用类型别名定义对象类型
type Point = {
  x: number;
  y: number;
};

// 使用类型别名
const point: Point = {
  x: 10,
  y: 20
};

// 函数参数和返回值
function calculateDistance(p1: Point, p2: Point): number {
  const dx = p1.x - p2.x;
  const dy = p1.y - p2.y;
  return Math.sqrt(dx * dx + dy * dy);
}

const distance = calculateDistance(
  { x: 0, y: 0 },
  { x: 3, y: 4 }
); // 5

为联合类型创建别名

类型别名非常适合定义联合类型(Union Types):

typescript
// 定义状态类型
type Status = "pending" | "success" | "error";

// 使用状态类型
function handleStatus(status: Status): void {
  switch (status) {
    case "pending":
      console.log("处理中...");
      break;
    case "success":
      console.log("成功");
      break;
    case "error":
      console.log("错误");
      break;
  }
}

// ✅ 正确
handleStatus("pending");
handleStatus("success");

// ❌ 错误:类型不匹配
// handleStatus("unknown");  // Error: Type '"unknown"' is not assignable to type 'Status'

为交叉类型创建别名

类型别名也可以用于定义交叉类型(Intersection Types):

typescript
// 定义基础类型
type Person = {
  name: string;
  age: number;
};

type Employee = {
  employeeId: string;
  department: string;
};

// 使用交叉类型组合多个类型
type EmployeePerson = Person & Employee;

// EmployeePerson 包含 Person 和 Employee 的所有属性
const employee: EmployeePerson = {
  name: "Alice",
  age: 30,
  employeeId: "E001",
  department: "Engineering"
};

为函数类型创建别名

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

typescript
// 定义函数类型别名
type MathOperation = (a: number, b: number) => number;

// 使用函数类型别名
const add: MathOperation = (a, b) => a + b;
const subtract: MathOperation = (a, b) => a - b;
const multiply: MathOperation = (a, b) => a * b;

// 函数参数使用函数类型
function calculate(
  operation: MathOperation,
  x: number,
  y: number
): number {
  return operation(x, y);
}

console.log(calculate(add, 5, 3));        // 8
console.log(calculate(subtract, 5, 3));  // 2
console.log(calculate(multiply, 5, 3));   // 15

为元组类型创建别名

类型别名可以定义元组类型:

typescript
// 定义元组类型别名
type Coordinate = [number, number];
type RGB = [number, number, number];

// 使用元组类型
const point: Coordinate = [10, 20];
const color: RGB = [255, 128, 0];

// 函数返回元组
function getCoordinates(): Coordinate {
  return [0, 0];
}

// 解构元组
const [x, y] = getCoordinates();

高级用法

泛型类型别名

类型别名支持泛型,可以创建可复用的类型定义:

typescript
// 定义泛型类型别名
type Container<T> = {
  value: T;
  isEmpty: boolean;
};

// 使用泛型类型别名
const stringContainer: Container<string> = {
  value: "Hello",
  isEmpty: false
};

const numberContainer: Container<number> = {
  value: 42,
  isEmpty: false
};

// 泛型函数使用泛型类型别名
function createContainer<T>(value: T): Container<T> {
  return {
    value,
    isEmpty: false
  };
}

const container = createContainer("TypeScript");

条件类型别名

类型别名可以结合条件类型使用:

typescript
// 定义条件类型别名
type NonNullable<T> = T extends null | undefined ? never : T;

// 使用条件类型
type StringType = NonNullable<string | null>;  // string
type NumberType = NonNullable<number | undefined>;  // number

// 实际应用:提取数组元素类型
type ArrayElement<T> = T extends (infer U)[] ? U : never;

type StringArrayElement = ArrayElement<string[]>;  // string
type NumberArrayElement = ArrayElement<number[]>;  // number

映射类型别名

类型别名可以结合映射类型使用:

typescript
// 定义映射类型别名
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

type Partial<T> = {
  [P in keyof T]?: T[P];
};

// 使用映射类型
type User = {
  name: string;
  age: number;
  email: string;
};

type ReadonlyUser = Readonly<User>;
// 等同于:
// {
//   readonly name: string;
//   readonly age: number;
//   readonly email: string;
// }

type PartialUser = Partial<User>;
// 等同于:
// {
//   name?: string;
//   age?: number;
//   email?: string;
// }

递归类型别名

类型别名支持递归定义,可以表示树形结构等复杂类型:

typescript
// 定义递归类型别名:树节点
type TreeNode<T> = {
  value: T;
  children?: TreeNode<T>[];
};

// 使用递归类型
const tree: TreeNode<string> = {
  value: "root",
  children: [
    {
      value: "child1",
      children: [
        { value: "grandchild1" },
        { value: "grandchild2" }
      ]
    },
    {
      value: "child2"
    }
  ]
};

// 递归类型:JSON 值
type JSONValue =
  | string
  | number
  | boolean
  | null
  | JSONValue[]
  | { [key: string]: JSONValue };

const jsonData: JSONValue = {
  name: "John",
  age: 30,
  tags: ["developer", "typescript"],
  metadata: {
    active: true,
    scores: [95, 87, 92]
  }
};

类型别名与接口的区别

类型别名和接口在很多场景下可以互换使用,但它们有一些重要区别:

1. 声明合并(Declaration Merging)

接口支持声明合并,类型别名不支持

typescript
// 接口:可以多次声明,会自动合并
interface Window {
  title: string;
}

interface Window {
  width: number;
}

// 合并后的 Window 包含 title 和 width
const window: Window = {
  title: "My Window",
  width: 800
};

// 类型别名:不能重复声明
type Window = {
  title: string;
};

// ❌ 错误:重复声明类型别名
// type Window = {
//   width: number;
// };  // Error: Duplicate identifier 'Window'

2. 扩展方式

接口使用 extends,类型别名使用交叉类型 &

typescript
// 接口扩展
interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

// 类型别名扩展(使用交叉类型)
type AnimalType = {
  name: string;
};

type DogType = AnimalType & {
  breed: string;
};

3. 适用场景

接口更适合

  • 定义对象结构
  • 需要声明合并的场景
  • 与类一起使用(implements

类型别名更适合

  • 定义联合类型
  • 定义交叉类型
  • 定义函数类型
  • 定义元组类型
  • 定义复杂的类型组合
typescript
// 接口:适合对象结构
interface User {
  name: string;
  age: number;
}

// 类型别名:适合联合类型
type Status = "active" | "inactive" | "pending";

// 类型别名:适合函数类型
type EventHandler = (event: Event) => void;

// 类型别名:适合复杂组合
type ApiResponse<T> = 
  | { status: "success"; data: T }
  | { status: "error"; message: string };

使用示例

示例 1:API 响应类型

typescript
// 定义 API 响应类型
type ApiResponse<T> =
  | { status: "success"; data: T; code: 200 }
  | { status: "error"; message: string; code: number };

// 使用泛型类型别名
type UserResponse = ApiResponse<{
  id: number;
  name: string;
  email: string;
}>;

// 处理响应
function handleResponse<T>(response: ApiResponse<T>): void {
  if (response.status === "success") {
    console.log("Success:", response.data);
  } else {
    console.log("Error:", response.message, response.code);
  }
}

// 创建响应对象
const successResponse: UserResponse = {
  status: "success",
  data: {
    id: 1,
    name: "John",
    email: "john@example.com"
  },
  code: 200
};

const errorResponse: UserResponse = {
  status: "error",
  message: "User not found",
  code: 404
};

handleResponse(successResponse);  // ✅ 正确
handleResponse(errorResponse);    // ✅ 正确

示例 2:事件处理系统

typescript
// 定义事件类型
type EventType = "click" | "hover" | "focus" | "blur";

// 定义事件处理器类型
type EventHandler<T extends EventType> = (event: {
  type: T;
  target: HTMLElement;
  timestamp: number;
}) => void;

// 定义事件映射类型
type EventMap = {
  click: EventHandler<"click">;
  hover: EventHandler<"hover">;
  focus: EventHandler<"focus">;
  blur: EventHandler<"blur">;
};

// 事件管理器
class EventManager {
  private handlers: Partial<EventMap> = {};

  on<T extends EventType>(type: T, handler: EventHandler<T>): void {
    this.handlers[type] = handler as EventMap[T];
  }

  emit<T extends EventType>(type: T, event: Parameters<EventHandler<T>>[0]): void {
    const handler = this.handlers[type];
    if (handler) {
      handler(event as any);
    }
  }
}

// 使用示例
const manager = new EventManager();

manager.on("click", (event) => {
  console.log("Clicked:", event.target, event.timestamp);
});

manager.emit("click", {
  type: "click",
  target: document.body,
  timestamp: Date.now()
});

示例 3:状态管理类型

typescript
// 定义状态类型
type LoadingState = {
  status: "loading";
};

type SuccessState<T> = {
  status: "success";
  data: T;
};

type ErrorState = {
  status: "error";
  error: string;
};

// 使用联合类型定义状态
type AsyncState<T> = LoadingState | SuccessState<T> | ErrorState;

// 使用示例
type User = {
  id: number;
  name: string;
};

type UserState = AsyncState<User>;

// 状态处理函数
function handleUserState(state: UserState): void {
  switch (state.status) {
    case "loading":
      console.log("加载中...");
      break;
    case "success":
      console.log("用户数据:", state.data);
      break;
    case "error":
      console.log("错误:", state.error);
      break;
  }
}

// 创建不同状态
const loadingState: UserState = { status: "loading" };
const successState: UserState = {
  status: "success",
  data: { id: 1, name: "John" }
};
const errorState: UserState = {
  status: "error",
  error: "Failed to load user"
};

handleUserState(loadingState);  // "加载中..."
handleUserState(successState); // "用户数据: { id: 1, name: 'John' }"
handleUserState(errorState);   // "错误: Failed to load user"

示例 4:工具函数类型

typescript
// 定义工具函数类型
type Predicate<T> = (item: T) => boolean;
type Mapper<T, U> = (item: T) => U;
type Reducer<T, U> = (accumulator: U, item: T) => U;

// 使用类型别名定义工具函数
function filter<T>(array: T[], predicate: Predicate<T>): T[] {
  return array.filter(predicate);
}

function map<T, U>(array: T[], mapper: Mapper<T, U>): U[] {
  return array.map(mapper);
}

function reduce<T, U>(
  array: T[],
  reducer: Reducer<T, U>,
  initialValue: U
): U {
  return array.reduce(reducer, initialValue);
}

// 使用示例
const numbers = [1, 2, 3, 4, 5];

// 过滤偶数
const evens = filter(numbers, (n) => n % 2 === 0);  // [2, 4]

// 映射为字符串
const strings = map(numbers, (n) => n.toString());  // ["1", "2", "3", "4", "5"]

// 求和
const sum = reduce(numbers, (acc, n) => acc + n, 0);  // 15

类型检查示例

常见错误

typescript
// ❌ 错误:类型别名不能重复声明
type User = {
  name: string;
};

// type User = {
//   age: number;
// };  // Error: Duplicate identifier 'User'

// ❌ 错误:联合类型值不匹配
type Status = "active" | "inactive";

const status: Status = "pending";  // Error: Type '"pending"' is not assignable to type 'Status'

// ❌ 错误:缺少必需属性
type Person = {
  name: string;
  age: number;
};

const person: Person = {
  name: "John"
  // Error: Property 'age' is missing in type '{ name: string; }'
};

正确写法

typescript
// ✅ 正确:使用类型别名定义对象
type User = {
  name: string;
  age: number;
  email?: string;  // 可选属性
};

const user: User = {
  name: "John",
  age: 30
};

// ✅ 正确:使用联合类型
type Status = "active" | "inactive" | "pending";

const status: Status = "pending";  // ✅ 正确

// ✅ 正确:使用交叉类型扩展
type BaseUser = {
  name: string;
  age: number;
};

type AdminUser = BaseUser & {
  role: "admin";
  permissions: string[];
};

const admin: AdminUser = {
  name: "Alice",
  age: 30,
  role: "admin",
  permissions: ["read", "write", "delete"]
};

注意事项

提示

  • 类型别名提供了比接口更灵活的类型定义方式,特别适合定义联合类型、交叉类型和复杂类型组合
  • 使用类型别名可以提高代码的可读性和可维护性,特别是对于复杂的类型定义
  • 类型别名支持泛型,可以创建可复用的类型定义
  • 类型别名可以递归定义,适合表示树形结构等复杂数据结构

注意

  • 类型别名不支持声明合并(Declaration Merging),如果需要声明合并,应该使用接口
  • 类型别名是类型级别的,不会生成运行时代码,只在编译时进行类型检查
  • 复杂的类型别名可能难以理解,建议使用有意义的名称并添加注释
  • 类型别名不能使用 implementsextends 关键字,需要使用交叉类型 & 来扩展

信息

类型别名在以下场景特别有用:

  • 定义联合类型和交叉类型
  • 定义函数类型和回调函数类型
  • 定义复杂的类型组合和工具类型
  • 创建可复用的泛型类型定义
  • 定义递归类型结构

重要

  • 类型别名和接口各有优势,根据具体场景选择合适的方式
  • 对于对象结构,接口和类型别名都可以使用,但接口更适合需要声明合并的场景
  • 对于联合类型、交叉类型等复杂类型,类型别名是唯一选择
  • 理解类型别名与接口的区别,有助于在合适的场景选择合适的方式

相关链接

基于 VitePress 构建