假设我有这个基类
class BaseComponent<T> {
constructor(protected selectors: T) {}
}LoginComponent.ts
const ADMIN_SELECTORS = {
inputUserName: "foo",
buttonLogin: "bar",
textError: "baz",
};
class LoginComponent<T> extends BaseComponent<typeof ADMIN_SELECTORS> {
constructor(protected selectors: typeof ADMIN_SELECTORS) {
super(selectors);
}
get loginButton() {
return this.selectors.buttonLogin;
}
}
// EXAMPLE CALL
const login = new LoginComponent(ADMIN_SELECTORS);多亏了typeof ADMIN_SELECTORS,我告诉TypeScript,this.selectors的结构将是什么。这使我在使用this.selectors时可以自动完成和打字。
get userInput() {
return this.selectors.inputUser; // Property 'inputUser' does not exist on type '{ inputUserName: string; buttonLogin: string; textError: string; }'
}好的!
但是,我现在需要做的是创建一个子类CustomerLoginComponent。这个子类对于inputUserName和它的选择器对象中名为textCustomerName的新的唯一属性应该有不同的值。
CustomerLoginComponent.ts
const CUSTOMER_SELECTORS = {
inputUserName: "abc",
textCustomerName: "xyz",
};
class CustomerLoginComponent extends LoginComponent<typeof CUSTOMER_SELECTORS> {
constructor(selectors) {
super(selectors);
}
get customerName() {
return this.selectors.textCustomerName;
}
}
// EXAMPLE CALL
const customerLogin = new CustomerLoginComponent(CUSTOMER_SELECTORS);我在这里遇到的错误是代码的这一部分中的Property 'textCustomerName' does not exist on type '{ inputUserName: string; buttonLogin: string; textError: string; }':
get customerName() {
return this.selectors.textCustomerName;
}我决定要做的是调整LoginComponent
class LoginComponent<T> extends BaseComponent<typeof ADMIN_SELECTORS> {
constructor(protected selectors: typeof ADMIN_SELECTORS & T) { // Note ' & T'!
super(selectors);
}
get loginButton() {
return this.selectors.buttonLogin;
}
}现在,当我尝试使用CustomerLoginComponent时,没有错误。
但是,我现在想不出的是如何用CustomerLoginComponent对CustomerLoginComponent进行注释。基本上,TypeScript的建议是这样做:
class CustomerLoginComponent extends LoginComponent<typeof CUSTOMER_SELECTORS> {
constructor(selectors: { inputUserName: string; buttonLogin: string; textError: string; } & { inputUserName: string; textCustomerName: string; }) {
super(selectors);
}
}当然,我不能硬编码对象结构,因为它是一种“灵活”的对象(这就是我使用typeof__的原因)。另外,它还位于另一个文件中。
我的问题是,我能否让CustomerLoginComponent知道selectors的类型是两个合并的对象:
父类(我想应该以某种方式传递的类型)+ typeof CUSTOMER_SELECTORS。
我试着理解infer关键字,但我不确定这是我要找的.另外,我也不太确定这部分:
class LoginComponent<T> extends BaseComponent<typeof ADMIN_SELECTORS> {
constructor(protected selectors: typeof ADMIN_SELECTORS & T) {
}
}我想我的基类犯了个错误
class BaseComponent<T> {
constructor(protected selectors: T) {}
}由于我仍然必须显式地将LoginComponent中的选择器类型注释为: typeof ADMIN_SELECTORS,否则它将无法工作。
总之,正如您可能猜到的,上面的示例在设计中存在一些核心问题,因此,任何帮助都将不胜感激。
否则,我想知道如何在CustomerLoginComponent中注释选择器参数的类型。
发布于 2021-01-30 00:35:43
仿制药
你几乎和typeof ADMIN_SELECTORS & T在一起了。我认为您对BaseComponent和LoginComponent中的两个不同的LoginComponent泛型感到困惑,它们代表着不同的事物。T在BaseComponent中表示所有的选择器。LoginComponent知道它的选择器是typeof ADMIN_SELECTORS类型,所以它需要泛型的唯一原因是处理子类添加的附加属性。
T可以表示那些附加的选择器:
class LoginComponent<T = {}> extends BaseComponent<typeof ADMIN_SELECTORS & T> {或者T可以表示所有选择器:
class LoginComponent<T extends typeof ADMIN_SELECTORS = typeof ADMIN_SELECTORS> extends BaseComponent<T> {在这两种情况下,我都为T设置了一个默认值,以便它永远不是unknown。
构造器参数
现在我们来讨论哪些参数需要传递给构造函数,以及它们是什么类型。在所有三个类中,构造函数接受整个selectors对象。
这意味着您不能调用new CustomerLoginComponent(CUSTOMER_SELECTORS),因为您没有提供LoginComponent所需的管理选择器。你必须打电话给new CustomerLoginComponent({...ADMIN_SELECTORS, ...CUSTOMER_SELECTORS});
如果您不想这样做,我们需要使类从常量中获得选择器,而不是通过构造函数。通常来说,让class如此紧密地耦合到其数据并不是一个好主意,但是通过让类型依赖于typeof (常量),您已经在紧密耦合它。
class BaseComponent<T> {
constructor(protected selectors: T) {}
}
class LoginComponent<Extra = {}> extends BaseComponent<typeof ADMIN_SELECTORS & Extra> {
constructor(extraSelectors: Extra = {} as any) { // the typing here is not ideal because I wanted to make the extras optional
super({...extraSelectors, ...ADMIN_SELECTORS});
}
}
class CustomerLoginComponent extends LoginComponent<typeof CUSTOMER_SELECTORS> {
constructor() {
super(CUSTOMER_SELECTORS);
}
}
// EXAMPLE CALL
const login = new LoginComponent();
const customerLogin = new CustomerLoginComponent();https://stackoverflow.com/questions/65914503
复制相似问题