在 TypeScript 中,“类型体操”指的是借助映射类型、条件类型、infer类型推断等特性,在编译期对类型进行各种计算和转换,从而实现更强的类型安全和表达力。
类型体操的本质:在类型系统中实现逻辑运算和结构变换的能力。
值空间与类型空间
type MyType = string; // 类型空间
const myValue = "hello"; // 值空间
| 概念 |
类型空间 (Type Space) |
值空间 (Value Space) |
| 存在时间 |
编译阶段 |
运行时 |
| 存在哪儿 |
TypeScript 编译器里 |
JavaScript 执行时 |
| 内容示例 |
type, interface, typeof, extends, infer, keyof |
const, let, function, class, enum |
| 可用于 |
类型推导、类型检查 |
实际运行代码 |
| 最终输出 |
不会生成任何 JS 代码 |
会被编译成 JS 执行 |
所以类型体操就是围绕着类型空间来做逻辑处理的,例如实现如下功能:
type A = [number, string]
type DoubleA = [number, string, number, string] // 如何动态实现呢?
type Double<T extends any[]> = [...T, ...T]
type A = [number, string]
type DoubleA = Double<A> // [number, string, number, string]
类型的基础
// 原始值类型
type Name = string | number | boolean | null | undefined | symbol | bigint
// 字面量类型
type Name = 'a' | 'b' | 'c'
// 对象类型
type Name = {
name: string
age: number
}
// 索引签名(Index Signature)
type Name = {
[key: string]: number
}
// 数组类型
type Name = string[]
// 元组类型
type Name = [string, number]
// 函数类型
type Name = (n: number) => void
// 对象的调用签名类型
type Name = {
(n: number): void
}
结构性类型系统
结构性类型系统(Structural Typing),也叫类型兼容性(Type Compatibility),类型子集可以赋值给父集。
let foo = 123
let bar = 'hello'
bar = foo // error
// unknown: 所有类型的父集
let foo: string = 'hello'
let bar: unknown
bar = foo // ok
// never: 所有类型的子集
function foo(): never {
throw new Error("Something failed");
}
let bar: string = foo() // ok
let foo: string = 'hello' // 子集
let bar: string | number = 123 // 父集
bar = foo // ok
let foo: { username: string; age: number } = { username: 'zhangsan', age: 18 } // 子集
let bar: { username: string } = { username: 'zhangsan' } // 父集
bar = foo // ok
类型体操语法
1.函数
// 类型
type Fn<T> = T
type A = Fn<string> // string
2.对象
// 类型
type User = {
name: string
age: number
}
type A = User['name'] // ✔
type B = User.age // ✖
type C = User['name' | 'age'] // ✔
type D = User[keyof User] // ✔
3.数组
type Tuple = [string, number]
type A = Tuple[0] // string
type B = Tuple[1] // number
type C = Tuple[0 | 1] // string | number
type D = Tuple[number] // string | number
type Tuple = [string, number]
type A = [...Tuple] // [string, number]
type Tuple = [string, number]
type A = Tuple['length'] // 2
type Arr = string[]
type A = Arr[number] // string (number表示数组的任意索引,任意位置元素的类型)
4.条件
// 类型
// 条件类型:A 是否是 B 的子集
type IsNumber<T> = T extends number ? true : false
type A = IsNumber<1> // true
type B = IsNumber<'1'> // false
type C = IsNumber<number> // true
5.推断
// infer关键字 -> 类型推断
type Return<T> = T extends () => infer R ? R : never
type A = Return<() => number> // number
type B = Return<() => string> // string
type C = Return<boolean> // never
6.映射
// 类型
// 映射类型 in
type User = {
name: string
age: number
}
type A = {
[T in keyof User]: User[T]
}
7.循环
// 类型,只能用递归
type Loop<T extends number, R extends number[] = []> = R['length'] extends T ? R : Loop<T, [...R, R['length']]>
type A = Loop<5> // [0, 1, 2, 3, 4]
内置工具类型
在 TypeScript 中,内置工具类型(Built-in Utility Types) 是官方提供的一组强大的辅助类型,用来基于已有类型做出变换、约束或推导,帮助我们更灵活地操控类型系统。
// 内置工具类型
1. Partial<T>:将类型 T 的所有属性变为可选属性。
2. Required<T>:将类型 T 的所有可选属性变为必需属性。
3. Readonly<T>:将类型 T 的所有属性变为只读属性。
4. Record<K, T>:将类型 K 的所有属性映射到类型 T。
5. Pick<T, K>:从类型 T 中选择属性 K,返回一个新类型。
6. Omit<T, K>:从类型 T 中排除属性 K,返回一个新类型。
7. Exclude<T, U>:从类型 T 中排除类型 U,返回一个新类型。
8. Extract<T, U>:从类型 T 中提取类型 U,返回一个新类型。
9. NonNullable<T>:从类型 T 中排除 null 和 undefined,返回一个新类型。
10. ReturnType<T>:获取函数类型 T 的返回值类型。
11. InstanceType<T>:获取构造函数类型 T 的实例类型。
12. ThisType<T>:用于定义 this 的类型,通常用于函数类型的定义。
13. Parameters<T>:获取函数类型 T 的参数类型,返回一个元组类型。
14. ConstructorParameters<T>:获取构造函数类型 T 的参数类型,返回一个元组类型。
15. Unpack<T>:获取 Promise<T> 的类型,返回 T。
16. Awaited<T>:获取 Promise<T> 的类型,返回 T。
17. ThisParameterType<T>:获取函数类型 T 的 this 参数类型。
18. OmitThisParameter<T>:从函数类型 T 中排除 this 参数,返回一个新类型。
19. Uppercase<T>:将字符串字面量类型 T 转换为大写字母。
20. Lowercase<T>:将字符串字面量类型 T 转换为小写字母。
21. Capitalize<T>:将字符串字面量类型 T 的首字母转换为大写字母。
22. Uncapitalize<T>:将字符串字面量类型 T 的首字母转换为小写字母。
23. Awaited<T>:获取 Promise<T> 的类型,返回 T。
24. ThisParameterType<T>:获取函数类型 T 的 this 参数类型。
25. OmitThisParameter<T>:从函数类型 T 中排除 this 参数,返回一个新类型。
类型体操题库
地址: https://github.com/type-challenges/type-challenges
类型体操三方库
- type-fest
- ts-toolbelt
- utility-types
...
类型体操应用
- 组件库开发
- 框架开发
- 后端数据类型封装
- 表单校检
- 类型安全
...
以上便是对 TypeScript 类型体操的概要介绍。掌握这些高级类型操作,能让你在前端工程化项目中构建出更健壮、类型更安全的代码。如果你想与其他开发者交流更多技术细节,欢迎访问云栈社区。