如何在泛型类型中使用静态属性并使其有意义



我有一个构造函数,并调用static方法来设置一个静态变量。

export abstract class AbstractRepository<T extends Typegoose> {
private static conn: SessionDb<T>; // <-- Compile error here!
protected model: Model<InstanceType<T>, {}>;
constructor(entity: T, collectionName: string){
if(AbstractRepository.conn == null) AbstractRepository.conn = SessionDb.connect(entity);
this.model = AbstractRepository.conn.getModel(collectionName);
}  
}

如何键入conn: SessionDb <T>属性?
这个变量是一个mongoose连接。
保存一个singleton变量以备将来访问有意义吗?

问题

当您有一个泛型类时,泛型参数T应用于该类的每个实例。创建泛型类的实例时,可以像const myObj = new GenericClass<MyType>(args);那样指定类型T,但通常不需要这样做,因为构造函数签名告诉typescript用于创建实例的参数与泛型T的关系。

通过您的构造函数CCD_ 6,您已经告诉typescript";取变量CCD_ 7的类型并将其用作该实例的通用CCD_;。因此,当您通过调用const myObj = new ConcreteRepository(myEntity, myCollectionName);创建新实例时,typescript将确定myObj的类型为ConcreteRepository<typeof myEntity>。(我使用名称ConcreteRepository来描述一个扩展AbstractRepository的类,因为抽象类无法实例化(。

同时,static属性应用于类本身,因此应用于每个实例

您可以有许多AbstractRepository实例,它们可以具有许多不同的T值,但它们都共享相同的private static conn值。该变量的类型为T(因为它只设置了一次(,而不是当前实例的类型T

有一个依赖于泛型T的静态变量是没有意义的

解决方案1

为了确保每个实例都有一个与其实体类型对应的SessionDb,我们将conn设置为实例变量,而不是静态变量。每个实例都在构造函数中设置其onthis.conn

export abstract class AbstractRepository<T extends Typegoose> {
protected conn: SessionDb<T>;
protected model: Model<InstanceType<T>, {}>;
constructor(entity: T, collectionName: string){
this.conn = SessionDb.connect(entity);
this.model = this.conn.getModel(collectionName);
}
}

有了这个设置,基类可以通过类来实现,这些类本身就是通用的:

export class ConcreteRepository<T extends Typegoose> extends AbstractRepository<T> {
}

或者通过与T:的特定值绑定的类

export class SpecificRepository extends AbstractRepository<SpecificType> {
}

解决方案2

AbstractRepository是一个abstract类,这意味着它不能直接实例化,只能通过扩展它的类实例化来创建。如果这些扩展类都只适用于特定类型的实体,就像上面的SpecificRepository示例一样,那么每个特定的扩展类都可以有一个单独的static conn变量。

它看起来大概是这样的(我不知道其中一些类型的细节(:

export abstract class AbstractRepository<T extends Typegoose> {
protected model: Model<InstanceType<T>, {}>;
constructor(entity: T, collectionName: string){
this.model = this.getConnection().getModel(collectionName);
}
abstract getConnection(): SessionDb<T>;
}
export class SpecificRepository extends AbstractRepository<SpecificType> {
private static conn: SessionDb<SpecificType>;
getConnection(): SessionDb<SpecificType> {
if( SpecificRepository.conn === undefined) {
// would need to know about enity somehow, either by storing this.entity 
// or by having a static entity property on the class
SpecificRepository.conn = SessionDb.connect(entity);
}
return SpecificRepository.conn;
}
}

这里,基类声明每个具体化都必须有一个方法getConnection,该方法返回正确类型TSessionDb。我们已经把这个实现留给了孩子们来解决。但是由于我们知道这个方法必须存在,所以基类在执行this.model = this.getConnection().getModel(collectionName);时调用它是安全的

最新更新