资源栈 - www.zyz88.com

TypeScript高级类型编程:从条件类型到类型体操的实战指南

admin
2026-09-09 4 阅读 0 评论 0 点赞

TypeScript用了很久,但很多人还停留在”给变量加个类型注解”的阶段。其实TS的类型系统非常强大,掌握条件类型、映射类型、模板字面量类型等高级特性,能写出类型安全的工具函数和库,让IDE提示更精准,bug更少。本文从实用角度讲解TS高级类型的核心技巧。

为什么要学TypeScript高级类型

TypeScript已经成为前端开发的标配,但很多人只用到了基础类型注解。掌握高级类型编程,能让你的代码更安全、更智能,IDE提示更精准,还能写出类型安全的工具函数和库。本文从实用角度讲解TypeScript高级类型的核心技巧。

条件类型与infer

条件类型是TS类型编程的基础,语法类似三元表达式:

type IsString = T extends string ? true : false;

type A = IsString; // true
type B = IsString;     // false

infer关键字用于在条件类型中提取类型:

// 提取函数返回值类型
type ReturnType = T extends (...args: any[]) => infer R ? R : never;

type Fn = (a: number, b: string) => boolean;
type R = ReturnType; // boolean

// 提取Promise内部类型
type UnwrapPromise = T extends Promise ? U : T;
type P = UnwrapPromise<Promise>; // User

映射类型

映射类型可以基于已有类型创建新类型:

// 所有属性变为可选
type Partial = {
  [K in keyof T]?: T[K];
};

// 所有属性变为只读
type Readonly = {
  readonly [K in keyof T]: T[K];
};

// 自定义:所有属性变为可空
type Nullable = {
  [K in keyof T]: T[K] | null;
};

// 带as重映射:排除特定key
type RemoveId = {
  [K in keyof T as K extends 'id' ? never : K]: T[K];
};

模板字面量类型

TS 4.1引入的模板字面量类型,可以操作字符串类型:

type EventName = `on${Capitalize}`;
type ClickEvent = EventName; // 'onClick'

// 为对象的每个属性生成getter/setter
type Getters = {
  [K in keyof T as `get${Capitalize}`]: () => T[K];
};

interface User { name: string; age: number; }
type UserGetters = Getters;
// { getName: () => string; getAge: () => number; }

实用类型工具

工具类型 作用 示例
Partial<T> 所有属性可选 Partial<User>
Required<T> 所有属性必选 Required<Props>
Pick<T,K> 选取部分属性 Pick<User,’id’|’name’>
Omit<T,K> 排除部分属性 Omit<User,’password’>
Record<K,V> 键值对类型 Record<string,number>
ReturnType<T> 函数返回值 ReturnType<typeof fn>
Awaited<T> 解包Promise Awaited<Promise<User>>

类型体操实战

类型安全的事件总线

type EventMap = {
  click: { x: number; y: number };
  hover: { element: string };
  submit: { data: FormData };
};

class TypedEventBus<T extends Record> {
  private handlers = new Map<keyof T, Set void>>();

  on(event: K, handler: (payload: T[K]) => void) {
    if (!this.handlers.has(event)) {
      this.handlers.set(event, new Set());
    }
    this.handlers.get(event)!.add(handler);
  }

  emit(event: K, payload: T[K]) {
    this.handlers.get(event)?.forEach(h => h(payload));
  }
}

const bus = new TypedEventBus();
bus.on('click', ({ x, y }) => console.log(x, y)); // 类型安全
bus.emit('click', { x: 10, y: 20 }); // OK
bus.emit('click', { x: 10 }); // Error: 缺少y

深度只读

type DeepReadonly = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K];
};

interface Config {
  server: { host: string; port: number };
  debug: boolean;
}

const config: DeepReadonly = {
  server: { host: 'localhost', port: 3000 },
  debug: false,
};
config.server.host = 'other'; // Error: 只读

工程化实践

  • tsconfig严格模式——开启strict: true,包括noImplicitAny、strictNullChecks等
  • 类型导出规范——公共类型统一放在types目录,用export导出
  • 避免any——用unknown代替any,使用时进行类型收窄
  • 类型测试——用tsd或expect-type编写类型测试,确保类型变更不破坏API
  • 自动生成类型——后端API用OpenAPI/Swagger生成TS类型,前后端共享

TypeScript高级类型不是为了炫技,而是为了让代码更安全、更易维护。从实际需求出发,逐步引入高级类型技巧,才能发挥TypeScript的最大价值。

文章标题 TypeScript高级类型编程:从条件类型到类型体操的实战指南
本文由 资源栈 原创发布,转载请注明出处并保留原文链接。