typescript - 如何让通用工厂对不同类的构造函数进行类型检查?
问题描述
给定这个例子:
class OneArgConstructorClass {
constructor(name: string) {}
}
class TwoArgConstructorClass {
constructor(name: string, age: number) {}
}
class Creator<T>
{
constructor(tConstructor: new(...args: any[])=> T) {
const it: T = new tConstructor();
}
}
const e1 = new Creator<OneArgConstructorClass>(OneArgConstructorClass);
const e2 = new Creator<OneArgConstructorClass>(TwoArgConstructorClass);
为什么 e1 和 e2 是有效的陈述?typescript 不应该抱怨没有正确数量和类型的参数就无法正确构造 e1/e2 吗?是否可以根据传入的类构造函数对该示例进行正确的类型检查?
解决方案
没有错误的原因是您的tConstructor
参数采用任意数量的任何类型的参数。
如果您想更严格地限制允许哪些参数,您可以使用元组类型来准确指定哪些参数tConstructor
需要,例如:
class Creator<T>
{
constructor(tConstructor: new (...args: [string]) => T) {
// ^^^^^^^^
// note that args is a tuple containing exactly one item, namely a string
const it: T = new tConstructor();
// ^^^^^^^^^^^^^^^^^^
// This is now wrong because the constructor takes a string as parameter
}
}
const e1 = new Creator<OneArgConstructorClass>(OneArgConstructorClass);
const e2 = new Creator<OneArgConstructorClass>(TwoArgConstructorClass);
// ^^^^^^^^^^^^^^^^^^^^^^^
// This is now also wrong because the constructor signatures are not compatible
如果你做了...args
' 的签名[string, number]
,那么你的调用new tConstructor()
仍然是错误的,因为你没有给它它的 2 个必需参数,但是new Creator<OneArgConstructorClass>(TwoArgConstructorClass)
它现在接收到它正确的 2 个参数就可以了。
与您可能期望的不同,new Creator<OneArgConstructorClass>(OneArgConstructorClass)
它也不再抛出错误,因为接受 1 个参数的构造函数将安全地忽略它接收到的任何附加参数。
希望这可以帮助。
编辑
如果您想要一种调用类构造函数的类型安全方式,您需要执行以下操作:
// Note the constraint that T must be "new"able
class Creator<T extends new (...args: any[]) => any>
{
// ConstructorParameters is a builtin TS utility that when given a class returns the type of its parameters in a tuple
// Note that we need to pass the actual parameters in somehow; in this example I've made Creator#constructor take 2 parameters:
// 1) the class
// 2) its constructor parameters in a tuple
constructor(tConstructor: new (...args: ConstructorParameters<T>) => any,
argsArray: ConstructorParameters<T>) {
// Construct the class with the arguments array!
const it: T = new tConstructor(...argsArray);
}
}
// This will now work
const e1 = new Creator<typeof OneArgConstructorClass>(OneArgConstructorClass, ['hello']);
// This will now *not* work, which is correct, as the constructor signatures don't match
const e2 = new Creator<typeof OneArgConstructorClass>(TwoArgConstructorClass, ['hello', 14]);
// ^^^^^^^^^^^^^^^^^^^^^^
// Argument of type 'typeof TwoArgConstructorClass' is not assignable to parameter of type 'new (name: string) => any'.
// This *will* work because the signatures match
const e3 = new Creator<typeof TwoArgConstructorClass>(TwoArgConstructorClass, ['hello', 14]);
推荐阅读
- html - 如何使 p 和 h3 标签从相同的高度开始?
- spring - 跟踪所有方法方面
- java - 在标签中显示后如何从 ArrayList 中删除字符串?
- javascript - 为 for 循环中的选项项目提供颜色
- postgresql - 通过 SQLAlchemy 和 Flask 使用 PostgreSQL
- php - Symfony 表单提交 DateTime 格式
- sql - 获取转置的 SQL 结果
- binary - 如何做这个十六进制减法问题?
- css - 如何使 react-day-picker 宽以填充 Web 应用程序移动版本中的所有屏幕
- dart - 根据官方文档,颤振不显示图像