【发布时间】:2021-05-17 07:35:17
【问题描述】:
考虑以下示例:
class A {
private constructor(public n: number) {}
public getDouble() {
return this.n * 2;
}
static from(s: string): A;
static from(n: number): A;
static from(n1: number, n2: number): A;
static from(...args: unknown[]): A {
if (args.length === 1) {
if (typeof args[0] === 'string') {
if (args[0].length !== 1) {
throw new Error('String must have a length of 1')
}
return new A(Number(args[0]));
} else if (typeof args[0] === 'number') {
if (args[0] > 9) {
throw new Error('Number must be lower than 10')
}
return new A(args[0]);
}
} else if (args.length === 2) {
if (typeof args[0] === 'number' && typeof args[1] === 'number') {
const sum = args[0] + args[1];
if (sum > 9) {
throw new Error('Sum of numbers must be lower than 10')
}
return new A(sum);
}
}
throw new Error('No overload matched')
}
}
A 的实例只能使用静态方法from 构造,该方法被重载以获取字符串、数字或两个数字。有效参数仅包括长度为 1 的字符串、小于 10 的数字以及总和小于 10 的数字对 - 其他会导致错误。
我想实现另一个静态方法validate,它将检查是否可以从给定的参数列表构造A 的实例,如下所示:
static validate(...args: Parameters<typeof A.from>): boolean {
try {
A.from(...args);
return true;
} catch (error) {
return false;
}
}
问题在于 Parameters<typeof A.from> 解析为列表中最后一个重载的参数,在本例中为 n1: number, n2: number,这导致 TypeScript 不允许使用任何其他重载签名进行调用,即 A.validate('foo')。
如何让 TypeScript 理解 validate 可以使用与 from 相同的重载签名来调用?
我找到了两种可能的解决方案,但都有很大的缺点:
- 我可以手动构造另一个与之前所有重载匹配的重载签名并将其放在列表的末尾。但是,这将很难维护,并且会与 IntelliSense 提示混淆。
- 类似于 1.,但签名将允许
...args: unknown[]。然而,这会使 TypeScript 认为from实际上可以用任何参数调用,而实际上它不能。 - 我可以复制并粘贴所有
from重载签名,并将它们声明为validate。同样,难以维护 - 实际用例涉及更多的重载以及不止一个模仿from重载的静态方法,这将导致 50 多行重载声明。
还有其他方法可以解决这个问题吗?有没有办法写一个OverloadParameters 类型?
【问题讨论】:
标签: typescript