type-challenges:LastIndexOf

10 阅读1分钟

LastIndexOf

问题描述

实现类型版本的 Array.lastIndexOf, LastIndexOf<T, U> 接受数组 T, any 类型 U, 如果 U 存在于 T 中, 返回 U 在数组 T 中最后一个位置的索引, 不存在则返回 -1

For example:

type Res1 = LastIndexOf<[1, 2, 3, 2, 1], 2> // 3
type Res2 = LastIndexOf<[0, 0, 0], 2> // -1
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'type cases = [
  Expect<Equal<LastIndexOf<[1, 2, 3, 2, 1], 2>, 3>>,
  Expect<Equal<LastIndexOf<[2, 6, 3, 8, 4, 1, 7, 3, 9], 3>, 7>>,
  Expect<Equal<LastIndexOf<[0, 0, 0], 2>, -1>>,
  Expect<Equal<LastIndexOf<[string, 2, number, 'a', number, 1], number>, 4>>,
  Expect<Equal<LastIndexOf<[string, any, 1, number, 'a', any, 1], any>, 5>>,
]
​
​
// ============= Your Code Here =============
// 答案
type LastIndexOf<T extends any[], U> = T extends [...infer R,infer L]
  ? Equal<L, U> extends true
    ? R['length']
    : LastIndexOf<R, U>
  : -1

这道题和 IndexOf 逻辑很相似,如果要返回倒数第一个相同元素的索引,我们仍然需要用数组的长度来当成元素的索引返回,但是这里通过观察可以发现,实际上,如果按照原本IndexOf 的解题思路,这里的第三个泛型数组的长度并不能和倒数第一个相同元素的索引相同。

// indexOf 的解题思路
type IndexOf<T extends any[], U, A extends true[] = []> = T extends [infer F, ...infer R]
  ? Equal<F, U> extends true
    ? A['length']
    : IndexOf<R, U, [...A, true]>
  : -1

但是通过观察我们又发现,如果是从后往前判断元素是否和第二个泛型相同,那么前面的泛型数组的长度不正是当前泛型的索引嘛,也就是说, 泛型 L 的索引正是泛型 R 的长度。我们倒着判断第一个泛型中的元素是否和第二个泛型相同,如果不同则递归判断剩余元素,如果相同返回当前泛型 R 的长度即可。