typeorm: Node.JS Typescript TypeORM findOneBy({id: id}) fails in generic abstract class

Issue Description

Expected Behavior

No error

Actual Behavior

error TS2322: Type '{ id: number; }' is not assignable to type 'FindOptionsWhere<T> | FindOptionsWhere<T>[] | undefined'.

Steps to Reproduce

import { IRepository, EntityBase } from "core"
import { Database } from "../../db"
import { EntityTarget, Repository } from "typeorm"
export abstract class RepositoryBase<T extends EntityBase> implements IRepository<T> {
    protected _repository: Repository<T>;
    constructor(entity: EntityTarget<T>) {
        this._repository = Database.AppDataSource.getRepository(entity);
    }
    public async GetById (id: number): Promise<T | null> {
        return await this._repository.findOneOrFail({
            where: { id: id },
            relations: ["teachers"]
        });
    }
}

Using it in concrete class is OK.

My Environment

Dependency Version
Operating System Ubuntu 22.04
Node.js version v18.7.0
Typescript version 4.7.4
TypeORM version 0.3.7

Additional Context

Relevant Database Driver(s)

DB Type Reproducible
aurora-mysql no
aurora-postgres no
better-sqlite3 no
cockroachdb no
cordova no
expo no
mongodb no
mysql yes
nativescript no
oracle no
postgres no
react-native no
sap no
spanner no
sqlite no
sqlite-abstract no
sqljs no
sqlserver no

Are you willing to resolve this issue by submitting a Pull Request?

  • ✖️ No
  • ✖️ Yes, I have the time, but I don’t know how to start. I would need guidance.
  • ✖️ No, I don’t have the time, but I can support (using donations) development.
  • ✖️ No, I don’t have the time and I’m okay to wait for the community / maintainers to resolve this issue.

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 4
  • Comments: 18 (1 by maintainers)

Most upvoted comments

Looks like a similar issue has already been closed - #8939 While it does not really look fixed, people still complain both under this issue and the closed one. Is there any way to promote fixing it (it blocks us from upgrading library version from v0.2)?

Second this, there are several issues that are related to this exact same problem. Should we list them all here to get our point across?

https://github.com/typeorm/typeorm/issues/9671

https://github.com/typeorm/typeorm/issues/9508

https://github.com/typeorm/typeorm/issues/9350

https://github.com/typeorm/typeorm/issues/9346

https://github.com/typeorm/typeorm/issues/9269

https://github.com/typeorm/typeorm/issues/9251

https://github.com/typeorm/typeorm/issues/9223

and so on…

full list pretty much can be found here. https://github.com/typeorm/typeorm/issues?q=is+not+assignable+to+type+is%3Aopen

@khteh @pleerock @Ginden pinging you guys here as I’ve seen you closed the most issues related to this bug

There have been solutions made already to fix this issue, yet not yet pushed not merged. Can we please and please fix this as soon as possible?

https://github.com/typeorm/typeorm/issues/8939

This is a serious issue for the project because the whole orm is pretty much rendered unusable as a whole since years now, if one want’s to use custom typings in their queries they simply can’t use it. And casting to any or anything else is just a recipe for disaster and bugs.

Needless to say that most are forced to use older versions and have npm complain all the time about various issues. Pretty much can’t be used with latest nestjs or any framework that relies on latest typeorm version.

If you don’t have the time and resources to fix this then at least please let us know, and let’s work on the issue together so we can resolve it, as it affects a lot of people as indicated by the number of issues, and reactions opened for this bugs.

Otherwise most are left with no choice but use another orm framework, which would be a pitty considering the number of features typeorm supports and the effort put into this project.

I have the same problem. Is there a solution?

Hi! I want to share my solution. Maybe it will be helpful for somebody.

export interface BaseEntityInterface {
  readonly id: string;
  readonly createdAt: Date;
  readonly updatedAt: Date;
}

export abstract class BaseEntity implements BaseEntityInterface {
  @PrimaryGeneratedColumn('uuid')
  public id: string;

  @CreateDateColumn({ type: 'timestamptz' })
  public createdAt: Date;

  @UpdateDateColumn({ type: 'timestamptz' })
  public updatedAt: Date;
}

export interface BaseRepositoryInterface<T> {
  create(entity: T): Promise<T>;
  update(entity: T): Promise<T>;
  findOneById(id: string): Promise<T>;
  findAll(): Promise<T[]>;
  delete(id: string): Promise<DeleteResult>;
}

export abstract class BaseAbstractRepository<T extends BaseEntity>
  implements BaseRepositoryInterface<T>
{
  private repository: Repository<T>;

  protected constructor(repository: Repository<T>) {
    this.repository = repository;
  }

  public async create(entity: T): Promise<T> {
    return await this.repository.save(entity);
  }

  public async update(entity: T): Promise<T> {
    return await this.repository.save(entity);
  }

  public async findOneById(id: string): Promise<T> {
    return await this.repository.findOne({ where: { id } as FindOptionsWhere<T> });
  }
  
  public async findAll(): Promise<T[]> {
    return await this.repository.find();
  }

  public async delete(id: string): Promise<DeleteResult> {
    return await this.repository.delete(id);
  }
}