Typescript Generic Repository - 实例化通用类型
Typescript Generic Repository - instantiate the generic type
我正在尝试在 Typescript 中构建一个通用存储库(使用 DynamoDB,但这不相关)。
我有一个基本存储库 class,它接收一个通用类型。在这个 class 上,我有一个 getById
方法,它应该 return 实体对象作为通用 class:
的实例
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);
}
}
不确定是否可以不创建特定的构造函数,您只需将实体传递给 super()
。
TS 确实需要一个具体类型,因此它知道要调用哪个构造函数。幸运的是,有一种方法可以提供 - 通过通用 class 的构造函数。它看起来像这样:
class BaseRepository<T> {
private create: { new (): T; };
constructor(create: { new (): T; }) {
this.create = create;
}
getById(id: string): T {
...
let inst: T = new this.create();
...
};
}
我正在尝试在 Typescript 中构建一个通用存储库(使用 DynamoDB,但这不相关)。
我有一个基本存储库 class,它接收一个通用类型。在这个 class 上,我有一个 getById
方法,它应该 return 实体对象作为通用 class:
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);
}
}
不确定是否可以不创建特定的构造函数,您只需将实体传递给 super()
。
TS 确实需要一个具体类型,因此它知道要调用哪个构造函数。幸运的是,有一种方法可以提供 - 通过通用 class 的构造函数。它看起来像这样:
class BaseRepository<T> {
private create: { new (): T; };
constructor(create: { new (): T; }) {
this.create = create;
}
getById(id: string): T {
...
let inst: T = new this.create();
...
};
}