我想将不同类型的任意数量的参数传递给函数并使用这些类型。看起来like following:
function f<A>(a: A): A;
function f<A, B>(a: A, b: B): A & B;
function f<A, B, C>(a: A, b: B, c: C): A & B & C;
function f<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
function f(...args: any[]) {
return Object.assign({}, ...args);
}
var smth = f({ x: 1 }, { y: 2 }, { z: 3 });
var res = smth.x + smth.y + smth.z;
由于我想要任意数量的参数,我想摆脱这些声明
function f<A>(a: A): A;
function f<A, B>(a: A, b: B): A & B;
function f<A, B, C>(a: A, b: B, c: C): A & B & C;
function f<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
并使用单个声明,如:
function f<...T>(args: [...T]): &<...T>;
但这件事在语法上是错误的。
有没有办法以正确的方式重写它?
答案 0 :(得分:1)
虽然其他人提到Proposal: Variadic Kinds会帮助完成此任务,但我们可以为您的具体示例找到一些解决方法。
如果我们使用单个类型参数编写函数签名,我们可以获得参数的联合类型:
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;
}
这种方法的问题在于,如果我们使用类而不是对象文字,编译器将拒绝推断联合并给我们一个错误。如果我们让rest参数去(...
)并且只使用数组,编译器将推断出参数类型的并集:
function f<A>(args: A[]): A { /*…*/}
var smth = f([{ x: 1 }, new A(), new B()]);
typeof smth == A | B | {
x: number;
}
所以现在我们有一个类型的联合,但你想要一个交集。我们可以使用条件类型将并集转换为交集(请参阅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;
希望这会有所帮助,并且至少在我们获得可变类型之前为您提供可用的解决方法。