IndexOf
Less than 1 minuteTC-Medium
IndexOf
Problem
Implement the type version of Array.indexOf, IndexOf<T, U> takes an Array T, any U and returns the index of the first U in Array T.
type Res = IndexOf<[1, 2, 3], 2> // 1
type Res1 = IndexOf<[2, 6, 3, 8, 4, 1, 7, 3, 9], 3> // 2
type Res2 = IndexOf<[0, 0, 0], 2> // -1Solution
Approach: Linear Scan with Index Counter
Walk through the tuple, comparing each element to U using IsEqual.
type IsEqual<A, B> =
(<T>() => T extends A ? 1 : 2) extends
(<T>() => T extends B ? 1 : 2)
? true : false
type IndexOf<T extends unknown[], U, Count extends unknown[] = []> =
T extends [infer Head, ...infer Tail]
? IsEqual<Head, U> extends true
? Count['length']
: IndexOf<Tail, U, [...Count, unknown]>
: -1How it works:
- Extract
HeadfromTand compare toUusing the strictIsEqualhelper. - If equal, return
Count['length']as the current index. - Otherwise, recurse on
TailwithCountincremented. - If
Tis empty, return-1(not found).
Why use IsEqual instead of extends?
Simple extends doesn't distinguish any, never, or literal vs. union types correctly. The IsEqual trick using conditional type identity is fully strict.
Key Takeaways
IsEqualvia the<T>() => T extends A ? 1 : 2trick is the standard way to do strict equality in TypeScript types.- Index tracking via tuple accumulator
Countis reusable across many array-scanning problems.
