TypeScript进阶知识点
文章目录
- 知识点
- 1. extends
- 2. infer
- 3. typeof
- 4. void
- 5. never
- 6. &
- 7. PromiseLike
- 8. // @ts-expect-error
- 9. Function
- 10. Array
- 11. object
- 12. as const
- 13. Awaited
- 14. 模板字符串
- 15. 分布式条件类型
- 16. 添加泛型变量
知识点
1. extends
- 在 TypeScript 里,extends 关键字有多种用途,常见于泛型约束、继承类以及条件类型中。
2. infer
- 这是 TypeScript 中的一个关键字,用于在条件类型里进行类型推断。它只能在 extends 子句的右侧使用,作用是让 TypeScript 自动推断出一个类型变量。
3. typeof
- 在 TypeScript 里,typeof 不仅可以在运行时使用,还能在类型层面使用,用于获取变量或值的类型。
4. void
- void 类型:表示函数没有返回值,但函数可以正常结束。
5. never
- never 类型表示永远不会出现的值的类型。在函数中,never 类型通常用来表示函数永远不会正常结束返回,即函数要么抛出异常,要么进入无限循环等情况。
6. &
- 交叉类型: 交叉类型会创建一个新类型,新类型包含了多个类型的所有属性(如果属性名相同,会进行合并等操作)。
7. PromiseLike
- TypeScript 标准库中定义的一个接口,用于描述具有和 Promise 类似行为的对象,即这些对象至少实现了 then 方法。以下将从定义、使用场景、与 Promise 的关系等方面详细介绍 PromiseLike。
8. // @ts-expect-error
- @ts-expect-error 注释的用途是告诉 TypeScript 编译器,你预料到在它下面的代码会产生类型错误,不过你有意保留这个错误。要是代码并没有产生类型错误,编译器就会给出 Unused ‘@ts-expect-error’ directive 提示。
9. Function
-
在 TypeScript 类型系统中,函数(Function)实际上是一种特殊的对象(object)。因此,在实现 DeepReadonly 类型工具时,应该先检查 T 是否为函数类型,再检查是否为普通对象,否则函数类型会被错误地处理为普通对象。
-
使用 T extends Function: 当你需要专门处理函数类型(如提取参数类型、返回值类型)时。
- 仅匹配函数类型(包括箭头函数和普通函数)
- 可以通过 infer 提取函数参数和返回值的类型(如 T extends (arg: infer P) => infer R)。
10. Array
-
TypeScript 中的数组本质上就是对象(Array<T> 是 object 的子类型),因此递归处理对象属性时无需单独处理,数组元素会被自动处理。
-
使用 T extends Array: 当你需要专门处理数组类型(如提取元素类型、处理数组方法)时。
- 仅匹配 数组类型(包括普通数组和元组)
- 可以通过 infer 提取数组元素的类型(如 T extends Array<infer U>)。
11. object
- 使用 T extends object:当你需要处理任意对象结构(包括数组、函数、普通对象)时,例如递归转换对象属性。
- 匹配所有非原始类型(即除 number、string、boolean、null、undefined、symbol 之外的类型)。包括:普通对象({})、数组([])、函数(() => void)、类实例、Date、RegExp 等
- 可以使用 keyof T 获取对象的键类型
12. as const
- 常量断言 as const 会告诉 TypeScript 编译器,把表达式视为不可变的值。这会产生以下影响:
字面量类型固化:让数组元素的类型变为具体的字面量类型,而非宽泛的基础类型。
数组变为只读元组:把数组转换为只读元组,其长度和元素类型都固定。
const promiseAllTest2 = PromiseAll([1, 2, Promise.resolve(3)] as const);
// 无 as const 时:数组元素类型会被推断为宽泛类型,[1, 2, Promise.resolve(3)] 的类型会是 (number | Promise<number>)[]
const arrWithoutConst = [1, 2, Promise.resolve(3)];
// 有 as const 时:数组会变成只读元组,元素类型为具体的字面量类型,[1, 2, Promise.resolve(3)] as const 的类型是 readonly [1, 2, Promise<3>]
const arrWithConst = [1, 2, Promise.resolve(3)] as const;
13. Awaited
- Awaited 是 TypeScript 4.5 引入的内置工具类型
- Awaited 类型能帮助你获取 Promise 解析后的值的类型。若传入的类型是 Promise,它会递归解析该 Promise 直至得到最终的非 Promise 类型;若传入的不是 Promise 类型,则直接返回该类型。
14. 模板字符串
// Expect<Equal<TrimLeft<" \n\t foo bar ">, "foo bar ">>
// 测试用例:传入字符串,返回去除左侧空格、换行符、制表符后的字符串
type TrimLeft<S extends string> = S extends `${" " | "\n" | "\t"}${infer R}`? TrimLeft<R>: S;
15. 分布式条件类型
- 在 TypeScript 里,分布式条件类型(Distributive Conditional Types)是一种强大的特性,它能让条件类型在处理联合类型时逐个处理每个成员。下面详细介绍其原理、使用场景和注意事项。
- 当条件类型的泛型参数是一个联合类型,并且该泛型参数在条件类型的 extends 左侧以裸类型(未被数组、元组、函数等包裹)出现时,分布式条件类型就会生效。此时,条件类型会对联合类型中的每个成员分别进行计算,最后将结果合并成一个新的联合类型。
// 若 T 是联合类型,Distributive 会对 T 中的每个成员分别应用条件判断,最终结果是每个成员判断结果的联合类型。
type Distributive<T> = T extends SomeType ? TrueType : FalseType;
/* ________________ */
type ToArray<T> = T extends any ? T[] : never;type StrOrNum = string | number;
type StrOrNumArray = ToArray<StrOrNum>;
// 等价于 string[] | number[]// 分布式条件类型展开过程
// ToArray<string | number>
// -> ToArray<string> | ToArray<number>
// -> string[] | number[]
16. 添加泛型变量
- 累加器,是一个元组类型,初始值为空数组,用于存储扁平化后的结果。
- 泛型变量 S 用于遍历联合类型中的每个成员,每次取出一个类型。
- 每次递归调用,将当前类型 S 转换为元组 [S],并与累加器 Acc 进行合并。
- 递归结束条件:当联合类型中的所有成员都被处理完,即 S 不再是联合类型,返回累加器 Acc。
// Expect<Equal<LengthOfString<'Sound! Euphonium'>, 16>>
type LengthOfString<S extends string,Acc extends number[] = []
> = S extends `${infer F}${infer Rest}`? LengthOfString<Rest, [...Acc, 1]>: Acc["length"];