Q:

How can I correctly type generic tuple rest parameters in TypeScript 3+?

Prior to TypeScript 3.0, inferring types for N-arity functions involved creating an arbitrary number of function overloads for known generic arguments, then writing the function implementation using something like any typed rest parameters. TypeScript 3.0 changed this, so that a generic type can extend any[], which acts as a generic tuple.
This change makes sense and works fine for me with generic parameters themselves, but I can't get the types to flow through to return types as I could prior to 3.0.
Here's an example:
const takeToPromise = <T>(obs$: Observable<T>): Promise<T> => 
    obs$.pipe(take(1)).toPromise();

export function resolveObservables(): Promise<any[]>;
export function resolveObservables<T1>(o1: Observable<T1>): Promise<[T1]>;
export function resolveObservables<T1, T2>(o1: Observable<T1>, o2: Observable<T2>): Promise<[T1, T2]>;
export function resolveObservables<T1, T2, T3>(o1: Observable<T1>, o2: Observable<T2>, o3: Observable<T3>): Promise<[T1, T2, T3]>;
// Etc on the overloads
export function resolveObservables(...obs: (Observable<any>)[]): Promise<any[]> {
   return Promise.all(obs.map(takeToPromise));
}

Let's say I have only 3 overloads (up to T3). If I use resolveObservables by spreading an array into the function call, in TS 3.0, I will get an error:

Expected 0-3 arguments, but got 0 or more.

I can use this just fine with a fixed arity call, but as soon as I try to spread, I get errors. Any attempts to make this work have failed in some way or another. For example:
export function resolveObservables<T, U extends Observable<T>[]>(...obs: U): Promise<T[]>;

Will fail to capture any types (types are {}).
Is there some way to modify these types so I can get types to flow through without losing the ability to use spread arguments? In cases where I am using spread, I don't really care about the types, and if I did, I assume I could just use a tuple type. But based on what I've tried so far, I can either use spread but lose types, or have types but can't use spread.
What am I missing here?

A:

We can get this to mostly work on 3.0, but for full tuple mapping support we will need to wait for 3.1.
Firstly you don't need the extra T parameter, just use a constraint of U extends Observable<any>[] This will infer the correct tuple type for U
To extract the result tuple type we can use a mapped and a conditional type to extract the result type from the observable. This is the part that almost works in 3.0. In 3.0 the mapped type will mangle the array type so that only indexing operations will still be OK on the resulting type, all methods will be of type never. 3.1 will make mapped types on tuples and arrays work more as expected (read PR for details) . 
export function resolveObservables
    <U extends Observable<any>[]>(...obs: U): Promise<ExtractObservableTypes<U>> {
    return null as any;
}

type ExtractObservableTypes<T> = {
    [P in keyof T] : T[P] extends Observable<infer U> ? U : never
}
let o!: Observable<number>
let o2!: Observable<string>

resolveObservables(o, o2).then(r => {
    r[0].toExponential // r[0] is number
    r[1].substring // r[1] is string
})

Playground link

