# Solving Type Challenge

I’ve been trying to solve some type challenges to understand typescript better.

I had a lot of fun with a few easy and medium challenges which involve implementing types.

One of which I really enjoyed implementing is `IndexOf<T, U>`

.

Basically it behaves like a regular `indexOf`

function, except we are dealing with types, not literal values

```
type A = IndexOf<[1, 2, 3], 2>; // A is 1
type B = IndexOf<[2, 6, 3, 7, 9, 3, 8, 10], 3>; // B is 2
type C = IndexOf<[0, 0, 0], 2>; // C is -1
```

I started with this:

```
type IndexOf<T extends any[], U> = T extends [U, ...any]?
0: (
T extends [...infer X, U, ...infer Y]?
X['length'] : (
T extends [...infer H, U]?
H['length'] : -1
)
)
```

Basically I was thinking along these lines,

- Try to detect U at the start of the the array-like structure represented by T
- If match, we return 0 else we try to detect U within T instead of at the beginning
- Else try to detect U at the end of T

It didn’t work. It took me a long time to realize (2) was impossible because if there are multiple `U`

in T, the type checker won’t be able to infer `X`

or `Y`

.

Next I thought of a recursive solution:

```
type IndexOf<T extends any[], U> = T extends [U, ...any]?
0: (
T extends [...infer X, U]?
X['length'] : (
T extends [any, ...infer M, any]?
1 + IndexOf<M, U> : -1
)
)
```

This didn’t even type check, because we are dealing with types and `1 + IndexOf<M, U>`

is not valid. How can we get position if there’s no way to increment?

What if we start matching recursively from the end of T?

Third attempt:

```
type ExactlySame<C, P> = C extends P? (P extends C? true : false) : false
type IndexOf<T extends any[], U> =T extends [...any, infer G]? (
ExactlySame<G, U> extends true?
(T extends [...infer H, any]?
(IndexOf<H, U> extends -1? H['length']: IndexOf<H, U>): never
):
(T extends [...infer H, any]? IndexOf<H, U> : -1)) : -1
```

This worked! Whenever we matched U at the end of T, the index of U is the length of the number of elements before U. However we cannot immediately return that length, because U may occur earlier in T. So we recurse with the part before U, `H`

. If the chain of recursive calls leads to -1, we then accept the index of the later match.