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();
    ...
  };
}