Reputation: 1
I have a function that takes in a parameter of type [unknown, ...unknown], that is given by a template. I want to call this function recursively, for each element in that tuple, until none are left, at which point it should stop. I tried the following:
type Tail<T extends [...unknown[]]> =
T extends [unknown, ...infer Tail]
? Tail
: never;
function foo<T extends [unknown, ...unknown[]]>(value: T) {
...
const [head, ...tail] = value;
if (value.length === 0) {
return;
}
foo<Tail<T>>(tail);
}
But I'm getting the error "Source provides no match for required element at position 0 in target".
I've tried creating a conditional type that returned never for empty tuples, but because I'm using the template for other parameters, it wouldn't allow that either, because then those parameters weren't compatible.
I've also tried having T only extend [...unknown[]], but then that shifted that issue to the const [head, ...tail] line, as then I don't necessarily have a 0th element and checking for length there doesn't work either.
Even tried using the check 0 in tail
and then typeof tail
to no avail.
Is there a way to restrict this type so it knows that it has at least one element there, or another way of writing this?
Upvotes: 0
Views: 285
Reputation: 415
Here is the example of how Tail
works on TypeScript Playground
type Tail<V> = V extends readonly [] ? V : V extends readonly [any?, ...infer VTail] ? VTail : V;
function foo<T extends unknown[]>(value: T) {
const [head, ...tail] = value;
console.log(`head:`, head);
// stop when no tail found
if (tail.length === 0) {
return;
}
// TypeScript can resolve `tail` by itself
foo(tail);
}
foo([1, "2", "3", 4]);
Upvotes: 0