简体   繁体   English

正确使用 typescript generics

[英]Using typescript generics properly

I have an interface of the following format which describes database methods like so:我有一个以下格式的接口,它描述了这样的数据库方法:

export default interface IRepository {
  createAndSave(data: ICreateUserDTO): Promise<User>
  findById<T>({ id }: { id: number }): Promise<T | null> // right here
  ...
}

As you can see from the snippet above, findById method is meant to take in a type and return a resolved promise of type T or a null value.正如您从上面的代码片段中看到的, findById方法旨在接受一个类型并返回T类型的已解析 promise 或 null 值。 I go-ahead to implement this in a class like so.我继续在 class 中实现这个,就像这样。

class DatabaseOps {
private ormManager: Repository<User>
...
async findById<User>({ id }: { id: number }): Promise<User | null> {
    const t = await this.ormManager.findOne({
      where: { id },
    }) 

    return t
  }
...
}

When I try to create the findById method like that, typescript gives this error of this format当我尝试创建这样的findById方法时,typescript 给出了这种格式的错误

Type 'import("../src/user/infra/typeorm/entities/User").default' is not assignable to type 'User'.
  'User' could be instantiated with an arbitrary type which could be unrelated to 'import("../src/audience/infra/typeorm/entities/User").default'

I tried to use typescript assertion to override this error like so我尝试使用 typescript 断言来覆盖这个错误,就像这样

class DatabaseOps {
private ormManager: Repository<User>
...
async findById<User>({ id }: { id: number }): Promise<User | null> {
    const t = await this.ormManager.findOne({
      where: { id },
    }) 

    return t as Promise<User> // here
  }
...
}

but I still get the error, I am not really sure what to do from this point onward.但我仍然收到错误,我不确定从现在开始该怎么做。

Here is what the User model definition looks like, I am making use of TypeORM这是用户 model 定义的样子,我正在使用 TypeORM

export default class User {
  @PrimaryGeneratedColumn('uuid')
  id: string

  @Column({
    type: 'json',
    nullable: true,
  })
  data: object

  @Column({ type: 'tinyint', default: 1 })
  status: number
  ...
}

What could be the cause of this and how do I rectify it?这可能是什么原因,我该如何纠正? Any help will be appreciated.任何帮助将不胜感激。 Thank you very much!非常感谢!

The IRepository.findById method's type signature doesn't mean what you think it means. IRepository.findById方法的类型签名并不意味着您认为它的含义。

When you write findById<T> , it means that the method promises to work with any type T .当您编写findById<T>时,这意味着该方法承诺适用于任何类型T Whoever calls the method chooses which type it is.调用该方法的人选择它是哪种类型。 Kind of like this:有点像这样:

const r : IRepository = ...
const x = r.findById<User>( ... )
const y = r.findById<number>( ... )
consy z = r.findById<string>( ... )
... and so on

And since the caller of the method can choose any type, it means that the implementer of the method must implement it such that it can work with any type.而且由于方法的调用者可以选择任何类型,这意味着方法的实现者必须实现它,以便它可以使用任何类型。 So it can't be just User .所以它不能只是User It has to be any type, whatever the caller happens to choose.它必须是任何类型,无论调用者碰巧选择什么。


Now, what you probably meant to do was to create not just a repository, but a repository of a certain thing .现在,您可能打算做的不仅仅是创建一个存储库,而是一个特定事物的存储库。 To do this, the generic parameter should be on the interface, not on the method:为此,泛型参数应该在接口上,而不是在方法上:

export default interface IRepository<T, DTO> {
  createAndSave(data: DTO): Promise<T>
  findById({ id }: { id: number }): Promise<T | null>
  ...
}

Then you can implement IRepository<User, ICreateUserDTO> in your class:然后您可以在 class 中实现IRepository<User, ICreateUserDTO>

class UserRepository {
    ...

    async createAndSave(data: ICreateUserDTO): Promise<User> {
        ...
    }

    async findById({ id }: { id: number }): Promise<User | null> {
        const t = await this.ormManager.findOne({
          where: { id },
        }) 

        return t as Promise<User> // here
      }

    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM