TypeScript 内置工具类型全解析

TypeScript 内置工具类型全解析:从 Pick/Omit 到 Awaited,打造类型安全的开发体验

本文全面梳理 TypeScript 官方提供的内置工具类型(Utility Types),帮助你告别重复定义接口,写出更简洁、健壮、可维护的类型代码。

🌟 为什么需要工具类型?

TypeScript 不仅是"带类型的 JavaScript",更是一个图灵完备的类型系统

在日常开发中,我们经常遇到这样的场景:

  • 一个用户接口 User,但编辑表单只需要部分字段;
  • 调用一个 API 函数,想自动获取它的返回类型;
  • 想把某个对象的所有属性变成可选,用于配置项;
  • 需要从联合类型中筛选出特定类型......

如果每次都手动写新接口,不仅繁琐,还容易出错,且难以同步变更。

TypeScript 的内置工具类型(Utility Types)正是为解决这些问题而生 。它们就像类型世界的 "Lodash"------提供一系列"函数",让你在编译期对类型进行操作,零运行时开销,却极大提升开发体验。


🔧 一、属性操作类:裁剪与修饰对象类型

这些是最常用的工具类型,用于对对象类型的属性进行"增删改"。

工具类型 作用 示例
Partial<T> T 的所有属性变为可选 Partial<{a: number}>{a?: number}
Required<T> T 的所有属性变为必填 Required<{a?: number}>{a: number}
Readonly<T> T 的所有属性变为只读 Readonly<{a: number}>{readonly a: number}
Pick<T, K> T选取 属性 K Pick<{a:1,b:2}, 'a'>{a:1}
Omit<T, K> T剔除 属性 K Omit<{a:1,b:2}, 'a'>{b:2}

1. Partial<T> ------ 所有属性变为可选

ts 复制代码
interface Config {
  host: string;
  port: number;
  ssl: boolean;
}

type OptionalConfig = Partial<Config>;
// 等价于:
// { host?: string; port?: number; ssl?: boolean }

适用场景:配置对象(提供默认值)、PATCH 请求体。


2. Required<T> ------ 所有属性变为必填

ts 复制代码
interface Options {
  timeout?: number;
  retries?: number;
}

type StrictOptions = Required<Options>;
// { timeout: number; retries: number }

适用场景:初始化完成后确保所有字段都已赋值。


3. Readonly<T> ------ 所有属性只读

ts 复制代码
interface State {
  count: number;
  name: string;
}

const state: Readonly<State> = { count: 0, name: "app" };
// state.count = 1; // ❌ 编译错误!

适用场景:状态管理、不可变数据。


4. Pick<T, K> ------ 选取指定属性

ts 复制代码
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

type UserInfo = Pick<User, 'id' | 'name'>;
// { id: number; name: string }

适用场景:API 返回简化版数据、组件 props 子集。


5. Omit<T, K> ------ 剔除指定属性

ts 复制代码
type PublicUser = Omit<User, 'password'>;
// { id: number; name: string; email: string }

适用场景:隐藏敏感字段(如密码、token)、避免属性冲突。

💡 记忆技巧:Pick = "我要这些",Omit = "我不要这些"


⚙️ 二、函数相关工具类型:从函数中提取类型信息

TypeScript 允许你"窥探"函数的内部结构,并提取其参数或返回值类型。

工具类型 作用 示例
ReturnType<T> 获取函数 T返回值类型 ReturnType<() => string>string
Parameters<T> 获取函数 T参数类型组成的元组 Parameters<(a: string) => void>[string]
Awaited<T> 递归解包 Promise(TS 4.5+) Awaited<Promise<string>>string Awaited<Promise<Promise<number>>>number

1. ReturnType<T> ------ 获取函数返回值类型

ts 复制代码
function fetchUser() {
  return { id: 1, name: "Alice" };
}

type User = ReturnType<typeof fetchUser>;
// { id: number; name: string }

适用场景:自动推导 API 返回类型,避免重复定义接口。


2. Parameters<T> ------ 获取函数参数元组

ts 复制代码
function greet(name: string, age: number) {}

type GreetParams = Parameters<typeof greet>;
// [string, number]

适用场景:高阶函数、函数包装器(如 debounce、throttle)。


3. Awaited<T> ------ 递归解包 Promise(TS 4.5+)

ts 复制代码
async function getData() {
  return { value: 42 };
}

type Data = Awaited<ReturnType<typeof getData>>;
// { value: number }

适用场景 :处理异步函数返回值,尤其在配合 ReturnType 时非常强大。


其他函数工具类型(较少用但有用):

工具类型 作用
ConstructorParameters<T> 获取构造函数参数类型(如 new Date(...)
InstanceType<T> 获取类的实例类型
ThisParameterType<T> / OmitThisParameter<T> 处理显式 this 参数

🧩 三、联合类型操作:筛选与过滤

当面对 'loading' | 'success' | 'error' 这样的联合类型时,如何提取或排除某些成员?

工具类型 作用 示例
Exclude<T, U> T排除 可赋值给 U 的类型 `Exclude<'a'
Extract<T, U> T提取 可赋值给 U 的类型 `Extract<'a'
NonNullable<T> 去除 T 中的 nullundefined `NonNullable<string

1. Exclude<T, U> ------ 排除可赋值给 U 的类型

ts 复制代码
type Status = 'loading' | 'success' | 'error';
type NonLoading = Exclude<Status, 'loading'>;
// 'success' | 'error'

2. Extract<T, U> ------ 提取可赋值给 U 的类型

ts 复制代码
type Numbers = number | string | boolean;
type OnlyNumbers = Extract<Numbers, number>;
// number

3. NonNullable<T> ------ 移除 null 和 undefined

ts 复制代码
type MaybeString = string | null | undefined;
type DefinitelyString = NonNullable<MaybeString>;
// string

适用场景:类型守卫后的类型收窄、处理可空值。


📦 四、其他实用工具类型

工具类型 作用 示例
Record<K, T> 构造一个对象类型,键为 K,值为 T `Record<'id'

Record<K, T> ------ 构造键值对对象

ts 复制代码
type Lang = 'en' | 'zh' | 'ja';
type Translations = Record<Lang, string>;

const i18n: Translations = {
  en: "Hello",
  zh: "你好",
  ja: "こんにちは"
};

适用场景:多语言配置、状态映射、字典结构。


🧪 五、高级技巧:组合使用工具类型

工具类型的真正威力在于组合嵌套

ts 复制代码
// 1. 只读的用户基本信息
type ReadonlyUserInfo = Readonly<Pick<User, 'id' | 'name'>>;

// 2. 用于更新的 DTO(去除 ID 和创建时间,其余可选)
type UpdateUserDTO = Partial<Omit<User, 'id' | 'createdAt'>>;

// 3. 从异步函数中提取深层数据类型
async function api() {
  return { data: { user: { id: 1 } }, status: 200 };
}
type UserId = Awaited<ReturnType<typeof api>>['data']['user']['id'];
// number

🔍 这就是 TypeScript 类型编程的魅力:声明式、组合式、零成本抽象


总结与学习建议

核心价值回顾:

  • 减少重复:不再手写相似接口;
  • 自动同步:源类型变更,派生类型自动更新;
  • 类型安全:在编译期捕获错误,而非等到运行时。

学习路径建议:

  1. 先掌握 PartialPickOmitRecord
  2. 再学 ReturnTypeParameters
  3. 然后理解 ExcludeExtractAwaited
  4. 最后尝试自己实现工具类型(如 DeepPartial)。

官方文档


💬 结语

TypeScript 的工具类型不是"语法糖",而是类型系统能力的体现。掌握它们,你不仅能写出更安全的代码,还能在团队中推动更规范的类型设计。


本文适用于 TypeScript 4.5+,所有示例均可在 TypeScript Playground 中运行验证。

相关推荐
Wect4 小时前
LeetCode 26.删除有序数组中的重复项:快慢指针的顺势应用
前端·typescript
踢球的打工仔6 小时前
typescript-基本类型
前端·javascript·typescript
ttod_qzstudio19 小时前
TypeScript严格模式下的undefined与null
typescript·null·undefined
王林不想说话1 天前
React自定义Hooks
前端·react.js·typescript
咖啡の猫1 天前
TypeScript 开发环境搭建
前端·javascript·typescript
咖啡の猫1 天前
TypeScript基本类型
linux·ubuntu·typescript
Sheldon一蓑烟雨任平生1 天前
Vue3 低代码平台项目实战(上)
低代码·typescript·vue3·低代码平台·问卷调查·json schema
Hao_Harrision1 天前
50天50个小项目 (React19 + Tailwindcss V4) ✨ | AutoTextEffect(自动打字机)
前端·typescript·react·tailwindcss·vite7
Sheldon一蓑烟雨任平生1 天前
Vue3 低代码平台项目实战(下)
低代码·typescript·vue3·低代码平台·json schema·vue3项目