I have this code, which works as written but requires ignoring the error Type instantiation is excessively deep and possibly infinite.
type Something<T> = () => T;
type SomethingParam<S extends Something<any>> = ReturnType<S>
type CombineSomethings<S1 extends Something<any>, S2 extends Something<any>> = Something<SomethingParam<S1> & SomethingParam<S2>>;
type First<A extends Array<any>> = A[0];
// from https://stackoverflow.com/a/56370310
type Rest<T extends any[]> = ((...t: T) => void) extends ((h: any, ...r: infer R) => void) ? R : never;
// @ts-ignore without specific input this type is infinitely recursive and barfs, even ignored it will be resolved correctly when called
type MergeAllThings<Sa extends Array<Something<any>>> = Rest<Sa> extends [] ? First<Sa> : CombineSomethings<First<Sa>, MergeAllThings<Rest<Sa>>>
type Merged = MergeAllThings<[() => ({foo: 'foo'}), () => ({bar: 'bar'})]>
In the code i have now, when i provide the array type to the generic, it gives me exactly what i'm looking for, but MergeAllThings
in its generic form, and any utilities that use it before actually calling it throw the recursion error.
The error makes sense, in the generic form the array has no length so it never hits the base case, but i'm not sure how else to write this.
I tried to find existing examples, like Object.assign
link that do basically the same thing, but the accepted practice seems to be to define overloads for every possible number of arguments up to a certain point and then have a fall through that returns any
, which i'd really rather not do.
Is there a way to accomplish what i'm trying to do legitimately in typescript?