我想使用 Factory Pattern使用 TypeScript 将原始数据转换为 User
。我有两种不同类型的 User
:Employee
和 Customer
。两者都扩展了基类并且编译没有问题。下面是这三个类的极其简化的版本。
abstract class User {
constructor(data: any) { }
static createFromServer<T extends User>(this: new (...args: any[]) => T, data: any): T {
return new this(data);
}
}
class Employee extends User {
static '@type' = 'Employee';
static createFromServer<T extends User>(this: new (...args: any[]) => T, data: any): T {
return new this(data);
}
}
class Customer extends User {
static '@type' = 'Customer';
static createFromServer<T extends User>(this: new (...args: any[]) => T, data: any): T {
return new this(data);
}
}
很简单。现在为工厂。我想创建一个工厂,它将获取从服务器返回的原始数据并将该数据转换为系统其余部分可以使用的内容(即 User
的实例)。我想要做的是
class UserFactory {
/**
* Vends a User constructed from the raw data from the server.
*
* @param userData (Object) - the User definition, as obtained from the server
*
* @return (User) the User initialized from `userData`
*/
static vend<T extends User>(userData: any): T {
switch (userData['@type']) {
case Employee['@type']:
return Employee.createFromServer(userData);
case Customer['@type']:
return Customer.createFromServer(userData);
default:
throw new Error('Unknown User type.');
}
}
}
正如您可能猜到的那样(因为我在这里并且周末没有放松),那是行不通的。我收到以下错误:
Type 'Employee' is not assignable to type 'T'.
由于 T
扩展了 User
并且 Employee
扩展了 User
而没有添加或删除任何东西(在此简化版本中),上面的方法似乎应该有效。更烦人的是,上面的内容似乎适用于其他语言(例如 Java(已测试)、C++),我只是不确定为什么它在这种情况下不起作用。
GitHub 上有人建议问题可能与 overloading the constructor 有关,但显然这不会发生在这里。
那么,为什么 Employee
不能分配给类型 T
? (如何)我可以让上面的工作?在 TypeScript 中有更好的方法来处理这个问题吗?正确答案将至少回答前 2 个问题。
附录
createFromServer()
在子类中被重新定义是有原因的。这是一个最低限度可重现的例子。构造函数实际上并不从服务器获取原始数据。相反,createFromServer()
将原始数据转换为构造函数可以理解的参数。
最佳答案
它不起作用,因为您编写了太多代码。您应该利用多态性。这意味着简单地从两个基类中删除静态工厂方法。
这种方式会如您所愿地工作,并且您需要维护的代码会更少。事实上,这就是为什么 User
类中的静态方法具有 this
类型并且 new
的包含类使用 的原因>这个
引用。它使派生类能够继承本质上具有更多派生类型的工厂
此外,这不是 Java。事实上,我想不出比 TypeScript 更像 Java 的语言
关于TypeScript 工厂子类不可分配给类型父类(super class),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47257273/