recursive conditional
I want to be able to use recursive conditional types.
In this type:
type MapParams<T extends any[]> =
((...t: T) => any) extends ((first: string, ...tail: infer TRest) => any) ?
Prepend<First<T>, MapParams<TRest>> :
Partial<T>;
I am making all elements optional except for the ones at the start that are strings. This fails as MapParams references itself so I get a Type alias 'MapParams' circularly references itself.(2456) error.
type Prepend<TFirst, TRest extends any[]> =
((head: TFirst, ...args: TRest) => any) extends ((...args: infer U) => any)
? U
: TRest;
type First<T extends any[]> = T extends [infer TFirst, ...any[]] ? TFirst : never;
type MapParams<T extends any[]> =
((...t: T) => any) extends ((first: string, ...tail: infer TRest) => any) ?
Prepend<First<T>, Partial<TRest>> : // should be Prepend<First<T>, MapParams<TRest>>
Partial<T>;
function myFunction(one: string, two: string, three: number, four: boolean) { }
function mappedFunction(...args: MapParams<Parameters<typeof myFunction>>) { }
mappedFunction("") // should NOT work - string at index 1 should be required
mappedFunction("", "") // should work
mappedFunction(undefined) // should not work
mappedFunction() // should not work
My suggestion meets these guidelines:
I can up with this inelegant solution that works but only handles up to 10 params
type MapOne<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapTwo<TRest>> : Partial<T>;
type MapTwo<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapThree<TRest>> : Partial<T>;
type MapThree<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapFour<TRest>> : Partial<T>;
type MapFour<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapFive<TRest>> : Partial<T>;
type MapFive<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapSix<TRest>> : Partial<T>;
type MapSix<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapSeven<TRest>> : Partial<T>;
type MapSeven<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapEight<TRest>> : Partial<T>;
type MapEight<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapNine<TRest>> : Partial<T>;
type MapNine<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, MapTen<TRest>> : Partial<T>;
type MapTen<T extends any[]> = ((...t: T) => any) extends ((f: string, ...t: infer TRest) => any) ? Prepend<First<T>, Partial<TRest>> : Partial<T>;
Duplicate of #26980, but yes, please.
@Roaders
Sounds like you could use trampolines (as a workaround)
https://github.com/microsoft/TypeScript/issues/26980#issuecomment-566214255
Or use ts-toolbelt and how they do recursion.
Most helpful comment
Duplicate of #26980, but yes, please.