type-challenges:IndexOf

29 阅读2分钟

IndexOf

问题描述

实现类型版本的 Array.indexOfindexOf < T,U > 接受一个Array T,任意 U 并返回 Array T 中第一个 U 的索引。

type Res = IndexOf<[1, 2, 3], 2>; // expected to be 1
type Res1 = IndexOf<[2,6,3,8,4,1,7,3,9], 3>; // expected to be 2
type Res2 = IndexOf<[0, 0, 0], 2>; // expected to be -1
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'type cases = [
  Expect<Equal<IndexOf<[1, 2, 3], 2>, 1>>,
  Expect<Equal<IndexOf<[2, 6, 3, 8, 4, 1, 7, 3, 9], 3>, 2>>,
  Expect<Equal<IndexOf<[0, 0, 0], 2>, -1>>,
  Expect<Equal<IndexOf<[string, 1, number, 'a'], number>, 2>>,
  Expect<Equal<IndexOf<[string, 1, number, 'a', any], any>, 4>>,
  Expect<Equal<IndexOf<[string, 'a'], 'a'>, 1>>,
  Expect<Equal<IndexOf<[any, 1], 1>, 1>>,
]
​
​
// ============= Your Code Here =============
type IndexOf<T extends any[], U, A extends any[] = []> = T extends [infer F, ...infer R]
  ? Equal<F, U> extends true
    ? A['length']
    : IndexOf<R, U, [...A, F]>
  : -1
​
​

做了不少类似的题,我们会发现,需要返回长度的时候,一般都是返回一个数组的长度,这道题的基本思路很简单,首先肯定是一个个判断第一个泛型中的元素是否和第二个泛型相等,如果相等,这返回该元素的索引,关键点就在于如何返回索引,通过之前的练习,实际上我们可以很容易得想到,一般返回长度的时候,都是返回一个数组的长度,所以这里需要引入第三个泛型参数来计数。

思路理清之后,我们来看实际操作一下,首先是约束泛型参数

  • T extends any[] 第一个泛型参数为数组
  • 第二个泛型参数为任意值
  • 第三个泛型参数为一个计数的空数组,数组中用任何值计数都可以,你可以约束泛型的参数为固定值的数组,如 A extends 1[] = [] 或者 A extends true[] = [],随你喜欢,这里我们实际上只需要数组的长度,和数组中元素是什么没太大关系

其次,需要一个个判断元素是否和第二个泛型相等,那么可以写出 T extends [infer F, ...infer R] ,如何判断相同可以使用 Equal ,如果相同,则返回数组的长度,也就是该元素的索引,如果不相同,则继续递归判断剩余元素是否和泛型 U 相同,并且跳过当前元素,将数组长度加1,切记,这里的泛型 A 中的元素取决于你定义的数组中需要什么类型,如果是 A extends 1[] = [] ,那么这里的递归就应该是 IndexOf<R, U, [...A, 1]>,如果是 A extends true[] = [] ,那么这里的递归就应该是 IndexOf<R, U, [...A, true]>。当条件不满足时,返回 -1