Typescript 将类型信息从父类拉到子类

Typescript 将类型信息从父类拉到子类,typescript,generics,Typescript,Generics,假设我有一个基类 class BaseComponent<T> { constructor(protected selectors: T) {} } 很好 但是,我现在需要做的是创建一个子类CustomerLoginComponent。 该子类的选择器对象中名为textCustomerName的新唯一属性上的inputUserNameplus应有不同的值 CustomerLoginComponent.ts const ADMIN_SELECTORS = { inpu

假设我有一个基类

class BaseComponent<T> {
    constructor(protected selectors: T) {}
}
很好

但是,我现在需要做的是创建一个子类
CustomerLoginComponent
。 该子类的选择器对象中名为
textCustomerName
的新唯一属性上的
inputUserName
plus应有不同的值

CustomerLoginComponent.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);
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);
我决定做的是调整
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;
    }
}

当然,我不能硬编码对象结构,因为它是一种“灵活”的对象(这就是为什么我使用
typeof
)。另外,它位于另一个文件中

我的问题是,我能否让
CustomerLoginComponent
知道
选择器的类型是两个合并对象:

父类中的一个(我想我应该以某种方式传递它的类型?+
typeofcustomer\u选择器

我试图理解
推断
关键字,但我不确定我要找的是什么。。。 此外,我对这一部分也不是很确定:

class LoginComponent<T> extends BaseComponent<typeof ADMIN_SELECTORS> {
    constructor(protected selectors: typeof ADMIN_SELECTORS & T) {
    }
}
classlogincomponent扩展了BaseComponent{
构造函数(受保护的选择器:管理员类型\u选择器&T){
}
}
我想我的基础班错了

class BaseComponent<T> {
    constructor(protected selectors: T) {}
}
类基本组件{
构造函数(受保护的选择器:T){}
}
由于我仍然必须将
LoginComponent
中的选择器类型显式注释为
:typeof ADMIN\u selectors
,否则它将无法工作

总而言之,正如您可能猜到的那样,上面的示例在设计中有一些核心问题,因此任何帮助都将不胜感激

否则,我想知道如何在
CustomerLoginComponent

泛型中注释选择器参数的类型 使用
类型的管理员选择器&T
,您就快到了。我想您会被
BaseComponent
LoginComponent
中代表不同事物的两个不同的
T
泛型弄糊涂了<
BaseComponent
中的code>T
表示所有选择器
LoginComponent
知道它的选择器是type
typeof ADMIN\u选择器
,所以它需要是泛型的唯一原因是处理由子类添加的附加属性

T
可以仅代表这些附加选择器:

class LoginComponent<T = {}> extends BaseComponent<typeof ADMIN_SELECTORS & T> {
class LoginComponent<T extends typeof ADMIN_SELECTORS = typeof ADMIN_SELECTORS> extends BaseComponent<T> {
在这两种情况下,我都为
T
设置了一个默认值,这样它就永远不会
未知

构造函数参数 现在我们来讨论需要传递给构造函数的参数以及它们的类型。在所有三个类中,构造函数接受整个
选择器
对象

这意味着您不能调用
new CustomerLoginComponent(客户选择器)
,因为您没有提供
LoginComponent
所需的管理员选择器。您必须调用
新的CustomerLoginComponent({…ADMIN\u SELECTORS,…CUSTOMER\u SELECTORS})

如果您不想这样做,我们需要这样做,以便类从常量而不是通过构造函数获取选择器。让
类与数据紧密耦合通常不是一个好主意,但是通过让键入依赖于常量的
类型,您已经将其紧密耦合了

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();
类基本组件{
构造函数(受保护的选择器:T){}
}
类LoginComponent扩展了BaseComponent{
构造函数(extraSelectors:Extra={}与任何构造函数一样){//这里的类型并不理想,因为我想让extras成为可选的
超级({…外部选择器,…管理员选择器});
}
}
类CustomerLoginComponent扩展了LoginComponent{
构造函数(){
超级(客户选择);
}
}
//示例调用
const login=new LoginComponent();
const customerLogin=new CustomerLoginComponent();

我假设您已经知道这一点,但如果您不知道,当您只调用
super(…args)
时,您可以省略构造函数。如果这不仅仅是一个示例,那么我建议删除这些选项,以避免与类型匹配出现任何问题。@101arrowz您会惊讶于我所知甚少:)您不介意发布一个答案来说明这一点吗?我不太明白这个意思
class LoginComponent<T = {}> extends BaseComponent<typeof ADMIN_SELECTORS & T> {
class LoginComponent<T extends typeof ADMIN_SELECTORS = typeof ADMIN_SELECTORS> extends BaseComponent<T> {
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();