一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第28天,点击查看活动详情。
题目四十六:flip-arguments
// template.ts
type FlipArguments<T> = any
// test-cases.ts
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<FlipArguments<() => boolean>, () => boolean>>,
Expect<Equal<FlipArguments<(foo: string) => number>, (foo: string) => number>>,
Expect<Equal<FlipArguments<(arg0: string, arg1: number, arg2: boolean) => void>, (arg0: boolean, arg1: number, arg2: string) => void>>,
]
实现类型版本的 lodash 中的 _.flip。
类型 FlipArguments<T> 需要函数类型 T,并返回一个新函数类型,该函数类型的返回类型与 T 相同,但参数相反。
相当于:将函数中的参数翻转
代码实现
- 原代码
type FlipArguments<T> = any
- 将函数进行解构
type FlipArguments<T> = T extends (...args: infer Args) => infer Result
? ...
: ...
- 如果解构不出来,则说明不是传入的
T不是函数,返回never
type FlipArguments<T> = T extends (...args: infer Args) => infer Result
? ...
: never
- 解构出来后,将
Args进行翻转
type FlipArguments<T> = T extends (...args: infer Args) => infer Result
? (...args: Reverse<Args>) => Result
: never
Reverse 函数我们上一题做过了
题目四十七:flattendepth
// template.ts
type FlattenDepth = any
// test-cases.ts
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<FlattenDepth<[]>, []>>,
Expect<Equal<FlattenDepth<[1, 2, 3, 4]>, [1, 2, 3, 4]>>,
Expect<Equal<FlattenDepth<[1, [2]]>, [1, 2]>>,
Expect<Equal<FlattenDepth<[1, 2, [3, 4], [[[5]]]], 2>, [1, 2, 3, 4, [5]]>>,
Expect<Equal<FlattenDepth<[1, 2, [3, 4], [[[5]]]]>, [1, 2, 3, 4, [[5]]]>>,
Expect<Equal<FlattenDepth<[1, [2, [3, [4, [5]]]]], 3>, [1, 2, 3, 4, [5]]>>,
Expect<Equal<FlattenDepth<[1, [2, [3, [4, [5]]]]], 19260817>, [1, 2, 3, 4, 5]>>,
]
测试用例
- 空数组直接返回
- 默认深度为 1
- 参数 1 是需要打平的数组,参数 2 是需要打平的深度
代码实现
- 原代码
type FlattenDepth = any
- 设置三个入参
- 参数1:需要打平的数组
- 参数2:需要打平的深度
- 参数3:默认空数组,使用其
['length']属性来判断当前深度
type FlattenDepth<T extends any[], C extends number = 1, U extends any[] = []> = any
- 开始遍历数组
T,使用extends方式,每次解构出来一个值,依次判断- 解构不出来的话,说明当前的
T是个空数组了,直接返回
- 解构不出来的话,说明当前的
type FlattenDepth<T extends any[], C extends number = 1, U extends any[] = []> = T extends [infer F, ...infer R]
? ...
: T
- 判断解构出来的第一个值
F(也就是当前循环的值)是否是一个数组- 如果不是数组,则进行下一次循环 (继续遍历剩下的数据
R)
- 如果不是数组,则进行下一次循环 (继续遍历剩下的数据
type FlattenDepth<T extends any[], C extends number = 1, U extends any[] = []> = T extends [infer F, ...infer R]
? F extends any[]
? ...
: [F, ...FlattenDepth<R, C, U>]
: T
- 如果解构出来的值
F是一个数组,则继续判断当前深度U是否已经是所需的深度C了- 如果已经达到所需的深度了,则直接返回,不进行数组打平操作
type FlattenDepth<T extends any[], C extends number = 1, U extends any[] = []> = T extends [infer F, ...infer R]
? F extends any[]
? U['length'] extends C
? [F, ...FlattenDepth<R, C, U>]
: ...
: [F, ...FlattenDepth<R, C, U>]
: T
- 否则就是需要进行数组打平操作了
- 这里我们可以知道肯定是返回一个数组
- 数组会处理解构出来的两个值 (
F和R) - 对
F进行深一层的打平(U添加一个属性,使其length多1) - 对
R接着进行遍历
type FlattenDepth<T extends any[], C extends number = 1, U extends any[] = []> = T extends [infer F, ...infer R]
? F extends any[]
? U['length'] extends C
? [F, ...FlattenDepth<R, C, U>]
: [...FlattenDepth<F, C, [0, ...U]>, ...FlattenDepth<R, C, U>]
: [F, ...FlattenDepth<R, C, U>]
: T