Typescript泛型存储库-实例化泛型类型



我正在尝试用Typescript构建一个通用存储库(使用DynamoDB,但这并不相关(。

我有一个接收泛型类型的基本存储库类。在这个类上,我有一个getById方法,它应该将实体对象作为泛型类的实例返回:

export abstract class BaseRepository<T> implements WriteInterface<T>, ReadInterface<T> {
getById(id: string): Promise<T> {
const findParams = {
TableName: this.tableName,
Key: { id }
}
return this.documentClient.get(findParams).promise().then((data) => {
// this next line is my problem
// Ideally, I would just instantiate with the new() keyword.
let inst: T = new T(data.Item);
return inst;
});
}
}

上面的错误是

error TS2693: 'T' only refers to a type, but is being used as a value here.
96       let inst: T = new T(data.Item);

还有一些类似的问题,最常见的答案是使用工厂函数。这种方法的问题是,您仍然需要一个具体的类型来传递给工厂,但我正在尝试将工厂与泛型类型一起使用。

例如,从这里开始,我尝试进行

create<T>(type: {new(): T}): T {
let newEntity: T = new type();
return newEntity;
}
getById(id: string): Promise<T> {
const findParams = {
TableName: this.tableName,
Key: { id }
}
return this.documentClient.get(findParams).promise().then((data) => {
let inst: T = this.create(T);
return inst;
});
}

上面呈现了与以前完全相同的错误。

我很确定有可能实现我正在尝试的目标,因为我认为TypeORM做了一些非常相似的事情,但我找不到/不明白它是如何工作的。

后期编辑

因此,多亏了Nadia的回答,解决方案似乎仍然是一个工厂函数,但我缺少的是通过构造函数传递类型。因此,正确的实现应该是:

export abstract class BaseRepository<T> implements WriteInterface<T>, ReadInterface<T> {
protected tableName: string;
protected documentClient: AWS.DynamoDB.DocumentClient;
private create: {new (): T;};
constructor(tableName: string, create: { new (): T; }) {
this.create = create;
this.tableName = tableName;
this.documentClient = new AWS.DynamoDB.DocumentClient();
}
getById(id: string): Promise<T> {
const findParams = {
TableName: this.tableName,
Key: { id }
}
return this.documentClient.get(findParams).promise().then((data) => {
let inst: T = new this.create();
return inst;
});
}
}

然后,当我想扩展这个基本存储库时,方法是:

import { BaseRepository } from './base.repository';
const tableName = process.env.DDB_TOKENS_TABLE;
export class TokenRepository extends BaseRepository<TokenEntity> {
constructor() {
super(tableName, TokenEntity);
}
}

不确定是否存在不创建特定构造函数的wat,只需将实体传递给super()

TS确实需要一个具体的类型,这样它就知道要调用哪个构造函数。幸运的是,有一种方法可以提供-通过泛型类的构造函数。它看起来像这样:

class BaseRepository<T>  {
private create: { new (): T; };
constructor(create: { new (): T; }) {
this.create = create;
}
getById(id: string): T {
...
let inst: T = new this.create();
...
};
}

最新更新