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.