我想将任意数量的不同类型的参数传递给一个函数并使用这些类型。它看起来如下:
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;
Run Code Online (Sandbox Code Playgroud)
因为我想要任意数量的参数,所以我想去掉这些声明
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;
Run Code Online (Sandbox Code Playgroud)
并使用单个声明,如:
function f<...T>(args: [...T]): &<...T>;
Run Code Online (Sandbox Code Playgroud)
但这件事在语法上是错误的。
有没有办法以正确的方式重写它?
PS:同样的问题俄语。
编辑 3.0
虽然原始答案是正确的,但自从我第一次给它打字稿已经改变了。在 typescript 3.0 中,可以在 rest 参数中使用元组来捕获元组中参数的类型
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; }
Run Code Online (Sandbox Code Playgroud)
原答案
虽然正如其他人提到的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;
}
Run Code Online (Sandbox Code Playgroud)
这种方法的问题在于,如果我们使用类而不是对象字面量,编译器将拒绝推断联合并给我们一个错误。如果我们让 rest 参数 go ( ...) 并只使用一个数组,编译器将推断出参数类型的联合:
function f<A>(args: A[]): A { /*…*/}
var smth = f([{ x: 1 }, new A(), new B()]);
typeof smth == A | B | {
x: number;
}
Run Code Online (Sandbox Code Playgroud)
所以现在我们有一个类型的联合,但你想要一个交集。我们可以使用条件类型将联合转换为交集(请参阅此答案)
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;
Run Code Online (Sandbox Code Playgroud)
希望这会有所帮助,并至少在我们获得可变参数之前为您提供一个可用的解决方法。
| 归档时间: |
|
| 查看次数: |
8250 次 |
| 最近记录: |