为什么需要类型体操

TypeScript 的类型系统远不止简单的 stringnumber。当我们面对复杂的业务逻辑时,需要更强大的类型工具来保证代码的健壮性。

类型体操不是炫技,而是让编译器帮我们发现潜在的错误。

条件类型:类型的 if-else

type IsString<T> = T extends string ? true : false;

type A = IsString<string>;  // true
type B = IsString<number>;  // false

这个简单例子展示了条件类型的基本用法。更实用的场景是提取 Promise 的返回值类型:

type UnwrapPromise<T> = T extends Promise<infer R> ? R : T;

type Result = UnwrapPromise<Promise<string>>;  // string

映射类型:批量转换

type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

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

这些内置工具类型都是通过映射类型实现的。我们可以根据业务需求创建自定义的映射类型:

type Nullable<T> = {
  [P in keyof T]: T[P] | null;
};

模板字面量类型

从 TypeScript 4.1 开始,我们可以用模板字面量类型创建更精确的类型:

type EventName<T extends string> = `on${Capitalize<T>}`;

type UserEvent = EventName<'click' | 'hover'>;  // "onClick" | "onHover"

这在处理事件命名、CSS 属性等场景特别有用。

实战:API 响应类型推导

假设我们有一个统一的 API 响应格式:

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

// 使用
interface User {
  id: number;
  name: string;
}

async function fetchUser(): Promise<ApiResponse<User>> {
  // ...
}

通过泛型和条件类型的组合,我们能让 TypeScript 自动推导出响应数据的类型。

总结

类型体操的关键在于:

  • 理解类型系统的本质
  • 掌握条件类型、映射类型、infer 等核心工具
  • 从业务需求出发,不要过度设计

好的类型定义能让代码自文档化,提升团队协作效率。