微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Typescript Generic Repository - 实例化泛型类型

如何解决Typescript Generic Repository - 实例化泛型类型

我正在尝试在 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);

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

例如,从here我尝试过

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 BaseRepository<T>  {
private create: { new (): T; };
constructor(create: { new (): T; }) {
      this.create = create;
  }
getById(id: string): T {
    ...
    let inst: T = new this.create();
    ...
  };
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。