Edit for 3.0
While the original answer is correct, since I first gave it typescript has changed. In typescript 3.0 it is possible to use tuples in rest parameters to capture the type of the arguments in a tuple
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
function f<A extends any[]>(...args: A): UnionToIntersection<A[number]> { return null! }
var smth = f({ x: 1 }, new A(), new B()); // will have type A & B & { x: number; }
Original answer
While as others have mentioned Proposal: Variadic Kinds would help with this task, we can find some workarounds for your specific example.
If we write the function signature with a single type argument, we can get a union type of the arguments:
function f<A>(...args: A[]): A {}
var smth = f({ x: 1 }, { y: 2 }, { z: 3 });
typeof smth = {
x: number;
y?: undefined;
z?: undefined;
} | {
y: number;
x?: undefined;
z?: undefined;
} | {
z: number;
x?: undefined;
y?: undefined;
}
The problem with this approach is that if we use a class instead of an object literal the compiler will refuse to infer the union and give us an error instead. If we let the rest parameter go (...) and just use an array the compiler will infer a union of the parameter type:
function f<A>(args: A[]): A { /*…*/}
var smth = f([{ x: 1 }, new A(), new B()]);
typeof smth == A | B | {
x: number;
}
So now we have a union of types, but you want an intersection. We can convert the union to an intersection using conditional types (see this answer)
type UnionToIntersection<U> =
(U extends any ? (k: U)=>void : never) extends ((k: infer I)=>void) ? I : never
function f<A>(args: A[]): UnionToIntersection<A> {
return Object.assign({}, ...args);
}
class A { z: number }
class B { y: number }
var smth = f([{ x: 1 }, new A(), new B()]); // will have type A & B & { x: number; }
var res = smth.x + smth.y + smth.z;
Hope this helps, and gives you a usable workaround at least until we get variadic kinds.