IndexOf
问题描述
实现类型版本的 Array.indexOf
,indexOf < 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
。