一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第29天,点击查看活动详情。
TS类型展开
在 TS 类型中,我们进行类型的调用,有时会不显示对应的结果,只显示相关类型的调用
例如下面几个例子:
1、keyof
type obj10 = {
name: string
age: number
}
// 这里我们想要显示的是:name | age
// 实际的显示:keyof obj10
type keyofTest = keyof obj10
这里可以看出,TS 直接将对象的引用显示了出来,并没有将其内部展开
2、类型别名
type CxrObject = {
age: number
}
type CxrUnion = boolean | number
2.1、union
// 想要显示:boolean | number | string
// 实际显示:string | CxrObject
type unionCase = CxrObject | string
2.2、嵌套
type obj11 = {
c: CxrObject // 这里希望展开
// c: CxrUnion // 注意,之后的实现方法有个缺陷:对象中的 union 无法展开(但是单纯的union可以展开)
name: string
}
实现
keyof
对其进行判断后返回,即可展开
type Expand<T> = T extends infer O ? O : never
type r1 = Expand<keyofTest> // "name" | "age"
此时 r1 显示的内容:type r1 = "name" | "age"
类型别名
type r2 = Expand<unionCase> // string | CxrObject
展开类型别名(发现此时 Expand 并没有起作用),因为这里我们遇到的是对象,对象需要额外处理一下
- 改造
Expand函数
type Expand<T> = T extends infer O
? {[K in keyof O]: O[K]}
: never
type r3 = Expand<unionCase> // type r3 = string | { age: number; }
此时可以看到类型别名也已经展开了
递归/嵌套
type r4 = Expand<obj11> // type r4 = { c: CxrObject; name: string; }
如果传入的参数中有对象嵌套,则我们的 Expand 函数就又不好使了,那么我们接下来对其进行递归一下
- 改造
Expand函数
type Expand<T> = T extends object
? T extends infer O
? {[K in keyof O]: Expand<O[K]>}
: never
: T
type r5 = ExpandRecursive<obj11> // { c: { age: number; }; name: string; }
此时可以看到,我们已经正常展开了~
注意
这个方法有一个缺陷:如果对象内嵌套了联合类型,那么就没办法正常展开
type CxrUnion = boolean | number
type obj11 = {
c: CxrUnion // 对象中的 union 无法展开(但是单纯的union可以展开)
name: string
}
最终代码
type Expand<T> = T extends object
? T extends infer O
? {[K in keyof O]: Expand<O[K]>}
: never
: T