ts类型挑战【二十六】

199 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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
  • 否则就是需要进行数组打平操作了
    • 这里我们可以知道肯定是返回一个数组
    • 数组会处理解构出来的两个值 (FR
    • 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