I was wanting to use conditional types for a rest parameter but I was surprised when I did a test first
Here is a playground and here is the code:
type ExtractParts<P extends any[]> =
P extends [infer H, ...infer U]
? ['yes way']
: ['no way']
interface A {
description: string;
action: () => {
say: string;
it: string;
};
}
type Q = ExtractParts<[1,2,3]> // ['yes]
type P = ExtractParts<A[]>; // ['no way']
type R = ExtractParts<[{ // ['yes way']
description: string;
action: () => {
say: string;
it: string;
};
}]>;
I was surprised by this behaviour
type P = ExtractParts<A[]>; // ['no way']
But this works as I think because it is a strict tuple
type R = ExtractParts<[{ // ['yes way']
description: string;
action: () => {
say: string;
it: string;
};
}]>;
I wanted to use this technique with a rest parameter
type ExtractParts<P extends any[]> =
P extends [infer H, ...infer U]
? ['yes way']
: ['no way']
function parts<P extends any[]>(...parts: ExtractParts<P>){}
const b = parts(1,2,3);
But P extends [infer H, ...infer U]
returns false
Can I use conditional types like this to infer the head and tail for rest parameters?
The problem arises from the fact that an array can have 0 elements, while the tuple [H, ...T]
must have at least one element. You can define a tuple with an optional first element, [H?, ...T]
and that will be a base type for an array.
So in a conditional type you would use [(infer H)?, ...infer U]
type ExtractParts<P extends any[]> =
P extends [(infer H)?, ...infer U]
? ['yes way']
: ['no way']
interface A {
description: string;
action: () => {
say: string;
it: string;
};
}
type Q = ExtractParts<[1,2,3]> // ['yes way']
type P = ExtractParts<A[]>; // ['yes way']
Playground Link
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With