TypeScript 的类型体操(TypeScript Type Manipulation)是指通过类型系统进行复杂的类型操作和推断,以实现更灵活和强大的类型检查。
in keyof
跟 for ... in 相似,不过 in keyof 是用来操作类型的
interface Person {
name: string;
age: number;
location: string;
}
// 使用 keyof 获取对象的所有键
type PersonKeys = keyof Person; // 'name' | 'age' | 'location'
// 使用 keyof 获取对象的所有值
type PersonValues = Person[PersonKeys]; // string | number
// 使用 in keyof 获取对象的所有键值对
type PersonEntries = {
[K in PersonKeys]: Person[K];
};
// 封装通用工具
type GenericEntries<T> = {
[K in keyof T]: T[K];
};
type PersonEntries2 = GenericEntries<Person>;
Vue3源码中的类型体操
export type UnwrapRef<T> = T extends Ref<infer V>
? UnwrapRefSimple<V>
: UnwrapRefSimple<T>;
type UnwrapRefSimple<T> = T extends
| Function
| CollectioinTypes
| BaseTypes
| Ref
| RefUnwrapBailType[keyof RefUnwrapBailTypes]
? T
: T extends Array<any>
? {
[K in keyof T]: UnwrapRefSimple<T[K]>;
}
: T extends object
? UnwrappedObject<T>
: T;
代码解释
export type UnwrapRef<T> = T extends Ref<infer V>
? UnwrapRefSimple<V>
: UnwrapRefSimple<T>;
UnwrapRef
是一个类型别名,用于解包 Ref
类型。如果 T
是 Ref
类型,则提取其内部类型 V
并递归调用 UnwrapRefSimple
。否则,直接调用 UnwrapRefSimple
。
type UnwrapRefSimple<T> = T extends
| Function
| CollectioinTypes
| BaseTypes
| Ref
| RefUnwrapBailType[keyof RefUnwrapBailTypes]
? T
: T extends Array<any>
? {
[K in keyof T]: UnwrapRefSimple<T[K]>;
}
: T extends object
? UnwrappedObject<T>
: T;
UnwrapRefSimple
是一个类型别名,用于处理不同类型的解包逻辑:
基本类型检查:
T extends | Function | CollectioinTypes | BaseTypes | Ref | RefUnwrapBailType[keyof RefUnwrapBailTypes]
如果
T
是Function
、CollectioinTypes
、BaseTypes
、Ref
或RefUnwrapBailType
的某个键的类型,则直接返回T
。数组类型处理:
T extends Array<any>
如果
T
是数组类型,则递归解包数组的每个元素:{ [K in keyof T]: UnwrapRefSimple<T[K]>; }
对象类型处理:
T extends object
如果
T
是对象类型,则调用UnwrappedObject<T>
进行解包。其他类型: 如果
T
不符合上述任何一种情况,则直接返回T
。
类型体操的应用
类型体操在 TypeScript 中非常有用,特别是在以下场景中:
类型推断:通过条件类型和
infer
关键字,可以从复杂类型中提取子类型。类型转换:将一种类型转换为另一种类型,例如将联合类型转换为交叉类型。
类型保护:通过类型守卫和类型谓词,确保代码在运行时的类型安全。
类型映射:使用映射类型(如
keyof
和索引签名)来操作对象和数组类型。
示例
以下是一个简单的类型体操示例,用于提取函数的返回类型:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
function exampleFunction(): string {
return "Hello, TypeScript!";
}
type ExampleReturnType = ReturnType<typeof exampleFunction>; // ExampleReturnType = string
通过理解和掌握类型体操,你可以编写更强大和灵活的 TypeScript 代码,提高代码的类型安全性和可维护性。