携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
1. 引言
接着上一节中,接下来我们继续Ts中等篇的题型练习
https://github.com/type-challenges/type-challenges/blob/main/README.zh-CN.md 提供的TypeScript 类型体操姿势合集题型,目的是为了让大家更好的了解TS的类型系统,编写自己的类型工具,或者单纯的享受挑战的乐趣!
2. 题型
- Reverse: 实现类型版本的数组反转 Array.reverse
type a = Reverse<['a', 'b']> // ['b', 'a']
type b = Reverse<['a', 'b', 'c']> // ['c', 'b', 'a']
思路: 使用infer 关键字拆解对应元组元素,在使用递归方法循环操作获得反转元组; 解答:
type Reverse<T> = T extends [infer M,...infer N] ? [...Reverse<N>,M] : []
type Demo = Reverse<[]> // type Demo = []
type Demo1 = Reverse<['a', 'b']> // type Demo1 = ["b", "a"]
type Demo2 = Reverse<['a', 'b', 'c']> // type Demo2 = ["c", "b", "a"]
- Flip Arguments:实现lodash的_.flip的类型版本。
类型FlipArguments需要函数类型T,并返回一个新的函数类型,其返回类型与T相同,但参数相反。
type Flipped = FlipArguments<(arg0: string, arg1: number, arg2: boolean) => void>
// (arg0: boolean, arg1: number, arg2: string) => void
思路: 先定义一个reverse方法,该方法作用可以使元祖内部的元素倒转,此方法通过infer关键字结构配合递归本身函数,获得一个倒转的元祖,在通过js函数中的argument 代指传入数据值的数组集合,配合reverse把元祖内部元素倒转,配合输出倒转后的元祖函数,完成;
解答:
// your answers
type Reverse<T> = T extends [infer Head, ...infer Rest] ? [...Reverse<Rest>, Head] : T
type FlipArguments<T extends Function> = T extends (...args: infer A) => infer R ? (...args: Reverse<A>) => R : T
- FlattenDepth:递归地将数组平展到深度时间。
type a = FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2> // [1, 2, 3, 4, [5]]. flattern 2 times
type b = FlattenDepth<[1, 2, [3, 4], [[[5]]]]> // [1, 2, 3, 4, [[5]]]. Depth defaults to be 1
思路: 首先,①定义一个一次结构一层数组元素的FlattenOnce方法,该方法中,通过使用[]配合infer关键字,结构出每次要结构的元素和它以外的其他元素(等待结构),依次各项元素判断通过递归该函数结构;②定义一个IsFlatten 判断当前数祖各项是否为数祖的方法,还存在数组则返回false,否则代表数组已经“干净”,则返回true。 ③定义FlattenDepth方法,该方法需要传入三个参数:第一个参数代表判断对象,第二个需要结构的层数,第三个记录当前已经结构层数;先使用IsFlatten 判断当前初始对象本身是否已经是平铺到最底层的对象;如果是则无需判断直接回抛目标对象;如果不是判断当前的递归记录数组长度(等同于递归次数)是否已经满足第二参数所要求的平铺层数,如果是则回抛目标对象;如果以上都不是则执行FlattenDepth 递归函数本身,内部第一参数执行平铺一次数组的FlattenOnce 函数,第二参数保持不变传入题目要求的平铺数目;第三参数则利用递归函数的特性,传入一个记录当前递归函数次数的数组(没次递归新增传入数组一个any 字符用于拓展数组长度,为递归后的下次函数执行做铺垫);完成。 解答:
// 对 T 数组进行一次平铺
type FlattenOnce<T extends any[]> = T extends [infer F, ...infer R]
? [...(F extends any[] ? F : [F]), ...FlattenOnce<R>]
: []
// T 是否平铺的数组
type IsFlatten<T extends any[]> = T extends [infer F, ...infer R]
? (
F extends any[]
? false
: IsFlatten<R>
)
: true
type FlattenDepth<T extends any[], D extends number = 1, Reduce extends any[] = []> =
IsFlatten<T> extends true
? T
: (
Reduce['length'] extends D
? T
: FlattenDepth<FlattenOnce<T>, D, [any, ...Reduce]>
)