阮一峰《TypeScript 教程》学习笔记——类型工具
1. 一段话总结
TypeScript 提供 17个核心内置类型工具 与 4个字符串专用类型工具,核心工具覆盖Promise处理(如Awaited)、构造函数分析(如ConstructorParameters)、联合类型过滤(如Exclude/Extract)、对象属性调整(如Partial/Required/Pick/Omit)、函数参数与返回值提取(如Parameters/ReturnType)、数组只读化(ReadonlyArray)等场景;字符串工具则专注于大小写转换(如Uppercase/Capitalize)。这些工具基于类型映射、条件类型、infer等语法实现,可直接复用,避免重复编写类型逻辑,提升类型定义效率。
2. 思维导图

3. 详细总结
TypeScript 内置类型工具分为 核心类型工具(17个) 和 字符串专用类型工具(4个),前者覆盖Promise、构造函数、联合类型、对象、函数、数组等场景,后者专注于字符串大小写转换,均基于类型映射、条件类型等语法实现,可直接复用。
一、核心类型工具(17个)
按功能模块分类,结合作用、示例与实现,用表格展示:
| 功能模块 | 工具名称 | 核心作用 | 示例代码 | 实现逻辑(简化版) |
|---|---|---|---|---|
| Promise处理 | Awaited<Type> | 提取Promise的返回值类型,支持多重Promise | type T = Awaited<Promise<Promise<number>>>; // number | type Awaited<T> = T extends Promise<infer R> ? Awaited<R> : T; |
| 构造函数相关 | ConstructorParameters<Type> | 提取构造函数的参数类型,返回元组 | type T = ConstructorParameters<ErrorConstructor>; // [message?: string] | type ConstructorParameters<T> = T extends new (...args: infer P) => any ? P : never; |
InstanceType<Type> | 提取构造函数的实例类型 | type T = InstanceType<typeof Date>; // Date | type InstanceType<T> = T extends new (...args: any) => infer R ? R : any; | |
| 联合类型处理 | Exclude<UnionType, Excluded> | 从联合类型中删除与Excluded兼容的类型 | `type T = Exclude<‘a’ | ‘b’ |
Extract<UnionType, Target> | 从联合类型中提取与Target兼容的类型(与Exclude相反) | `type T = Extract<‘a’ | ‘b’ | |
NonNullable<Type> | 从联合类型中删除null和undefined | `type T = NonNullable<string | number | |
| 对象属性调整 | Partial<Type> | 将对象所有属性转为可选 | type T = Partial<{x:number; y:number}>; // {x?:number; y?:number} | type Partial<T> = { [P in keyof T]?: T[P]; } |
Required<Type> | 将对象所有属性转为必选(与Partial相反) | type T = Required<{x?:number; y:number}>; // {x:number; y:number} | type Required<T> = { [P in keyof T]-?: T[P]; } | |
Readonly<Type> | 将对象所有属性转为只读 | type T = Readonly<{x:number; y?:number}>; // {readonly x:number; ...} | type Readonly<T> = { readonly [P in keyof T]: T[P]; } | |
Pick<Type, Keys> | 从对象中提取指定Keys对应的属性(Keys需为对象已有属性) | type T = Pick<{x:number; y:number}, 'x'>; // {x:number} | type Pick<T, K extends keyof T> = { [P in K]: T[P]; } | |
Omit<Type, Keys> | 从对象中删除指定Keys对应的属性(Keys可不存在) | type T = Omit<{x:number; y:number}, 'x'>; // {y:number} | type Omit<T, K> = Pick<T, Exclude<keyof T, K>>; | |
Record<Keys, Type> | 生成键名为Keys、键值类型为Type的对象类型(Keys需兼容string/number/symbol) | `type T = Record<‘a’ | ‘b’, number>; // {a:number; b:number}` | |
| 函数相关 | Parameters<Type> | 提取函数的参数类型,返回元组(含参数名) | type T = Parameters<(a:number, b:string)=>void>; // [a:number, b:string] | type Parameters<T> = T extends (...args: infer P) => any ? P : never; |
ReturnType<Type> | 提取函数的返回值类型 | type T = ReturnType<typeof Math.random>; // number | type ReturnType<T> = T extends (...args: any) => infer R ? R : any; | |
ThisParameterType<Type> | 提取函数中this参数的类型 | type T = ThisParameterType<(this: Number)=>string>; // number | type ThisParameterType<T> = T extends (this: infer U) => any ? U : unknown; | |
OmitThisParameter<Type> | 移除函数的this参数 | type T = OmitThisParameter<(this: Number)=>string>; // ()=>string | type OmitThisParameter<T> = T extends (...args: infer A) => infer R ? (...args:A)=>R : T; | |
ThisType<Type> | 指定对象/函数中this的类型(需配合交叉类型,依赖noImplicitThis开启) | let obj: {fn:()=>void} & ThisType<{x:number}>; | interface ThisType<T> {}(空接口,仅作类型提示) | |
| 数组相关 | ReadonlyArray<Type> | 生成只读数组类型(无修改方法如push/pop) | const arr: ReadonlyArray<string> = ['a']; arr.push('b'); // 报错 | interface ReadonlyArray<T> { readonly [n:number]: T; readonly length: number; } |
二、字符串类型工具(4个)
专注于字符串类型的大小写转换,底层依赖JavaScript字符操作方法,用表格展示:
| 工具名称 | 核心作用 | 示例代码 | 说明 |
|---|---|---|---|
Uppercase<StringType> | 字符串所有字符转为大写 | type T = Uppercase<'hello'>; // "HELLO" | 全大写转换 |
Lowercase<StringType> | 字符串所有字符转为小写 | type T = Lowercase<'HELLO'>; // "hello" | 全小写转换 |
Capitalize<StringType> | 字符串首字母转为大写 | type T = Capitalize<'hello'>; // "Hello" | 仅首字母大写 |
Uncapitalize<StringType> | 字符串首字母转为小写 | type T = Uncapitalize<'HELLO'>; // "hELLO" | 仅首字母小写 |
4. 关键问题
问题1:Exclude与Extract是TypeScript中处理联合类型的核心工具,二者的核心差异是什么?分别适用于哪些场景?请结合示例说明。
答案:
二者的核心差异在于对联合类型的处理逻辑相反,均基于条件类型实现,具体区别如下:
- 核心逻辑:
Exclude<UnionType, Excluded>:从UnionType中删除与Excluded兼容的类型(返回不兼容的类型);Extract<UnionType, Target>:从UnionType中提取与Target兼容的类型(返回兼容的类型)。
- 适用场景:
Exclude:需“排除不需要的类型”时使用(如从权限列表中排除“只读”权限);Extract:需“筛选需要的类型”时使用(如从权限列表中筛选“可写”权限)。
- 示例对比:
// 联合类型:所有权限 type Permissions = 'read'|'write'|'delete'|'admin';// Exclude:排除'admin'权限 type UserPerms = Exclude<Permissions, 'admin'>; // 'read'|'write'|'delete'// Extract:筛选含'read'或'write'的权限 type ReadWritePerms = Extract<Permissions, 'read'|'write'>; // 'read'|'write'
问题2:Awaited与ReturnType都可用于处理函数返回值类型,在处理异步函数(返回Promise)时,二者的使用差异是什么?请结合示例说明。
答案:
二者在处理异步函数时的核心差异在于是否自动解析Promise的返回值类型,具体区别如下:
- 核心能力:
Awaited<Type>:专门用于解析Promise类型,自动提取Promise的最终返回值类型(支持多重Promise嵌套);ReturnType<Type>:提取函数的“原始返回值类型”,若函数返回Promise,仅返回Promise类型本身,不解析内部值。
- 使用差异:
- 处理异步函数时,
Awaited需配合ReturnType使用(先通过ReturnType获取函数返回的Promise类型,再用Awaited解析内部值); - 直接使用
ReturnType无法获取Promise的内部值类型。
- 处理异步函数时,
- 示例对比:
// 异步函数:返回Promise<number> async function fetchNum(): Promise<number> {return 100; }// ReturnType:仅获取函数原始返回值(Promise<number>) type RawReturn = ReturnType<typeof fetchNum>; // Promise<number>// Awaited + ReturnType:解析Promise内部值(number) type ResolvedReturn = Awaited<ReturnType<typeof fetchNum>>; // number// 多重Promise嵌套:Awaited仍可解析 type NestedPromise = Promise<Promise<string>>; type ResolvedNested = Awaited<NestedPromise>; // string
问题3:ThisType<Type>是TypeScript中特殊的类型工具,其核心作用与使用条件是什么?与ThisParameterType有何差异?
答案:
一、ThisType<Type>的核心作用与使用条件
- 核心作用:
ThisType<Type>本身不生成新类型,仅用于为对象或函数中的this指定类型,需与其他类型组成交叉类型使用,提示TypeScript识别this的具体类型(避免this被推断为any)。 - 使用条件:
- 必须开启编译选项
noImplicitThis(否则TypeScript不严格检查this类型); - 需与对象/函数类型组成交叉类型(如
{ fn: ()=>void } & ThisType<{x:number}>)。
- 必须开启编译选项
二、与ThisParameterType的差异
| 对比维度 | ThisType<Type> | ThisParameterType<Type> |
|---|---|---|
| 核心功能 | 为对象/函数中的this指定类型(主动提示) | 提取函数已定义的this参数类型(被动提取) |
| 使用场景 | 定义对象/函数时,提前指定this类型 | 分析已有函数的this参数类型 |
| 依赖条件 | 需开启noImplicitThis,需配合交叉类型 | 无特殊编译选项依赖 |
| 示例 | let obj: {fn:()=>void} & ThisType<{x:number}> | type T = ThisParameterType<(this: Number)=>string> |
三、示例
// 开启noImplicitThis
interface ThisObj { x: number; log: ()=>void }// ThisType:为obj中的this指定类型为ThisObj
let obj: { print: ()=>void } & ThisType<ThisObj> = {print() {console.log(this.x); // 正确:this被识别为ThisObjthis.log(); // 正确:ThisObj含log方法this.y; // 报错:ThisObj无y属性}
};// ThisParameterType:提取函数的this类型
function foo(this: ThisObj) { this.log(); }
type FooThis = ThisParameterType<typeof foo>; // ThisObj
