首先看输入代码:
interface User {
id: number;
name: string;
password: string;
}
type ReadUser = Omit<User, 'password'>;
const type = typeOf<ReadUser>();
编译后的结果包含了几个关键的类型定义:
const __ΩOmit = ['T', 'K', () => __ΩPick, () => __ΩExclude, 'Omit', 'b!b"e!!e!!ge!"o$#o##w%y'];
const __ΩPick = ['T', 'K', 'Pick', 'l+e#!e"!fRb!b"Pde""N#!w#y'];
const __ΩExclude = ['T', 'U', 'Exclude', 'l6!Re$!RPe#!e$"qk#%QRb!b"Pde"!p)w#y'];
const __ΩUser = ['id', 'name', 'password', 'User', 'P\'4!&4"&4#Mw$y'];
const __ΩReadUser = [() => __ΩOmit, () => __ΩUser, "password", 'ReadUser', 'n".#o!#w$y'];
基本编码规则
每个类型定义的格式都是数组,以 __ΩUser
为例:
const __ΩUser = ['id', 'name', 'password', 'User', 'P\\'4!&4"&4#Mw$y'];
数组的组成:
- 前面的元素:属性名、类型参数或类型引用
- 最后一个元素:类型编码字符串 类型编码字符串的组成规则
以 ‘P’4!&4”&4#Mw$y’ 为例,让我们拆解每个字符的含义:
- ‘P’:表示这是一个对象类型(Property)
- ''':对象开始的标记
- ‘4’:表示属性类型(这里是number类型)
- ’!’:属性分隔符
- ’&‘:属性连接符
- ‘M’:表示这是一个模型(Model)
- ‘w’:表示类型定义的结束
- ‘y’:表示整个类型声明的结束 常见类型标记
P - Property(对象类型)
n - Named Type(命名类型)
b - Basic Type(基础类型)
l - List(列表/数组)
e - Expression(表达式)
o - Operation(操作)
R - Reference(引用)
让我们分析 ReadUser 的转换过程
type ReadUser = Omit<User, 'password'>;
编译结果:
const __ΩReadUser = [() => __ΩOmit, () => __ΩUser, "password", 'ReadUser', 'n".#o!#w$y'];
编码 ‘n”.#o!#w$y’ 的含义:
- ‘n’:表示这是一个命名类型
- ’”‘:类型参数开始
- ’.’:参数分隔符
- ’#‘:类型引用分隔符
- ‘o’:表示这是一个类型操作(这里是Omit操作)
- ’!’:参数分隔符
- ’#‘:类型引用分隔符
- ‘w’:类型定义结束
- ‘y’:声明结束
Omit类型的编码
const __ΩOmit = ['T', 'K', () => __ΩPick, () => __ΩExclude, 'Omit', 'b!b"e!!e!!ge!"o$#o##w%y'];
这个编码更复杂,因为Omit是通过Pick和Exclude组合实现的:
- ‘b!b”‘:表示两个类型参数T和K
- ‘e!!’:表示表达式开始
- ‘g’:表示泛型
- ‘o$#‘:表示操作符
- ‘w%‘:表示包装器结束 转换过程
当编译器处理 Omit<User, 'password'>
时:
- 首先识别这是一个类型操作
- 解析User类型定义
- 解析字面量类型 ‘password’
- 生成新的类型定义,移除指定的属性
- 最终生成运行时可用的类型信息