【问题标题】:Using typescript generics properly正确使用 typescript 泛型
【发布时间】:2021-02-25 06:53:17
【问题描述】:

我有一个如下格式的接口,它描述了这样的数据库方法:

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

从上面的 sn-p 中可以看出,findById 方法旨在接受一个类型并返回一个已解析的 T 类型的承诺或空值。我继续在这样的类中实现它。

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
  }
...
}

当我尝试像这样创建 findById 方法时,打字稿会给出这种格式的错误

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'

我尝试像这样使用 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
  }
...
}

但我仍然收到错误消息,我不确定从现在开始该怎么做。

这是用户模型定义的样子,我正在使用 TypeORM

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

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

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

这可能是什么原因,我该如何纠正?任何帮助将不胜感激。非常感谢!

【问题讨论】:

  • 接口定义中有id: number,但User类中有id: string

标签: javascript node.js typescript


【解决方案1】:

IRepository.findById 方法的类型签名并不像您认为的那样。

当您编写findById&lt;T&gt; 时,这意味着该方法承诺与any 类型T 一起使用。调用该方法的人选择它是哪种类型。有点像这样:

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

并且由于方法的调用者可以选择any类型,这意味着方法的实现者必须实现它以便它可以使用any类型。所以它不能只是User。它必须是 any 类型,无论调用者碰巧选择什么。


现在,您可能打算做的不仅仅是创建一个存储库,而是创建一个某个事物的存储库。为此,泛型参数应该在接口上,而不是在方法上:

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

然后你可以在你的类中实现IRepository&lt;User, ICreateUserDTO&gt;

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
      }

    ...
}

【讨论】:

    猜你喜欢
    • 2022-01-16
    • 1970-01-01
    • 2020-07-25
    • 2013-04-29
    • 1970-01-01
    • 2019-07-23
    • 2022-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多