【发布时间】:2021-05-27 15:35:06
【问题描述】:
我正在尝试设置一个工厂函数来创建抽象类的子类。 工厂函数应该与子类类型无关。
这是抽象类:
export abstract class AbstractWorkflowTrigger {
protected params: any = null;
protected configParams: any = null;
protected user: any = null;
protected expectedParams: any = {};
constructor(params: any = {}, user?: any, configParams: any = {}) {
this.params = {
...configParams,
...params
};
this.user = user;
this.checkParams();
}
protected checkParams() {
const missingParams = Object.keys(this.expectedParams).filter(
(e: any) => this.expectedParams[e].required && !Object.keys(this.params).includes(e)
);
if (missingParams.length > 0) {
throw Error(`Missing required param(s): ${missingParams.join(', ')}`);
}
for (const param in this.params) {
if (this.params.hasOwnProperty(param)) {
console.log(this.expectedParams);
if (!this.expectedParams.hasOwnProperty(param)) {
throw Error(`Unknown param '${param}'`);
}
if (typeof this.params[param] !== this.expectedParams[param].type) {
throw Error(
`Wrong type for param '${param}', expected '${
this.expectedParams[param].type
}', got '${typeof this.params[param]}' instead`
);
}
}
}
}
public abstract do(task: ITask): Promise<void>;
}
子类的例子:
class AddCommentWorkflowTrigger extends AbstractWorkflowTrigger {
expectedParams = {
comment: {
required: false,
type: 'string'
},
text: {
required: true,
type: 'string'
}
}
public async do(task: ITask): Promise<void> {
if (task.comments.length > 0) {
task.comments += "\n";
}
if (this.params.comment) {
task.comments += `${this.params.text} - ${this.params.comment}`
} else {
task.comments += `${this.params.text}`;
}
}
}
我需要一个工厂函数来运行 checkParams() 函数,因为 expectedParams 成员没有设置为抽象类的构造函数上的子类值,我真的不想运行它每个子类上的 constructor() 函数以保持 DRY。
我目前拥有的工厂函数:
export function workflowTriggerFactory(c: any, ...params: any[]): AbstractWorkflowTrigger {
const built = new c(params);
c.checkParams();
return built;
}
export const WorkflowTriggers = {
assign: AssignWorkflowTrigger,
setOwnershipToUser: SetOwnershipToUserWorkflowTrigger,
unsetOwnership: UnsetOwnershipWorkflowTrigger,
addComment: AddCommentWorkflowTrigger
};
应该是这样称呼的:
await this.executeTriggersOnTask(category.actions[action].triggers, task, params, user);
以前的用法(无法将expectedParams获取到子类值):
const action: AbstractWorkflowTrigger = new (WorkflowTriggers as any)[trigger](params, user);
我不确定如何为工厂函数键入 c 参数,因为我想保持类型安全,但使用 AbstractWorflowTrigger 不会让我在它上面运行 new。
我应该选择什么签名?
当 Abstract 类运行 checkParams() 时,也许您会看到一种更好的方法来获得高效的代码,同时将 expectedParams 设置为正确的值?
【问题讨论】:
-
我可能会为您提供解决方案,但我需要先在 TS 操场上闲逛一会儿。至于输入
c参数,您可以执行type Ctr<T> = new () => T之类的操作吗? -
您能否解释一下
params、configParams和expectedParams在您想要实现的目标方面的区别 -
params 是来自 HTTP POST 请求的参数,configParams 是在 YAML 文件中设置的参数,expectedParams 是 TriggerAction 预期的参数(是否需要)。
type Ctr<T> = new () => T在做什么? -
它定义了一个类型别名,给定一个泛型 T 类型可以使用 new 关键字实例化一个 T。试着把它放在文件的顶部,创建一个命名的空类,创建一个具有这种类型的变量,最后将该变量分配给命名的空类。您应该看到该类型捕获了实例化该类的能力。
-
是派生类还是泛型类应该定义预期的参数?
标签: javascript typescript