I have an array of values:
const array = ['b', 'a', 'b', 'a', 'c'] as const;
So the type is:
const array: readonly ["b", "a", "b", "a", "c"]
Now I want to create a type that filters the array, and returns a type of array with only the filtered elements. I've created a FilterArray
type, that does the trick, however, the indexes on the array are taken from the first array and not restarted.
type FilterArray<T extends readonly any[], V> = {
[I in keyof T as [Extract<T[I], V>] extends [never] ? never : I]: T[I];
}
If I filter now on typeof array
, I get these results:
filteredArray[3]
is also of type 'a', which is correct.
Is it possible to restart the index from 0? Or should I take another approach?
CodePudding user response:
The problem here is that you are using a mapped type with key remapping. Because of the key remapping, the resulting type of FilterArray
is not a tuple but an object type with the two properties 1
and 3
.
To get a tuple type as the result, you need a recursive type.
type FilterArray<T extends readonly any[], V> =
T extends readonly [infer L, ...infer R]
? L extends V
? [L, ...FilterArray<R, V>]
: [...FilterArray<R, V>]
: []
This type iterates through the array and adds matching elements to the output.
The resulting type would now look like this:
const filteredArray = {} as FilterArray<typeof array, "a">
// ^? ["a", "a"]