question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

InjectRepository with generic type T

See original GitHub issue

I’m submitting a…


[ ] Regression 
[ ] Bug report
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

I would like to be able to inject a Repository with a generic type. Do you think it is possible?

Current behavior

@Injectable()
export class ResourcesService<T> {
  constructor(
    @InjectRepository(T)                                // <-- error happens here
    private readonly repo: Repository<T>
  ) {}
}

Typescript error:

error TS2693: 'T' only refers to a type, but is being used as a value here.

This is the only way I can think of doing it, and it is not a valid way.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

8reactions
krazibitcommented, Apr 27, 2020

Finally managed to do it, below is a code snippet you might find useful

import {Type} from '@nestjs/common'
import {InjectRepository} from '@nestjs/typeorm'
import * as DataLoader from 'dataloader'
import {keyBy} from 'lodash'
import {Repository} from 'typeorm'

export interface IDataService<T> {
  readonly repository: Repository<T>
  load: (id: string | number) => Promise<T>
  loadMany: (ids: Array<string | number>) => Promise<T[]>
}

type Constructor<I> = new (...args: any[]) => I // Main Point

export function DataService<T>(entity: Constructor<T>): Type<IDataService<T>> {
  class DataServiceHost implements IDataService<T> {
    @InjectRepository(entity) public readonly repository: Repository<T>

    private get primaryColumnName(): string {
      return this.repository.metadata.primaryColumns[0]?.propertyName
    }

    private loader: DataLoader<number | string, T> = new DataLoader(async ids => {
      const entities = await this.repository.findByIds(ids as any[])
      const entitiesKeyed = keyBy(entities, this.primaryColumnName)
      return ids.map(id => entitiesKeyed[id])
    })

    public async load(id: string | number): Promise<T> {
      return this.loader.load(id)
    }

    public async loadMany(ids: Array<string | number>): Promise<T[]> {
      return this.loadMany(ids)
    }
  }
  return DataServiceHost
}

Not you can extend you services with this as explained by @BrunnerLivio here https://github.com/nestjs/typeorm/issues/187#issuecomment-528910193

0reactions
incompletudecommented, Mar 4, 2021

Finally managed to do it, below is a code snippet you might find useful

import {Type} from '@nestjs/common'
import {InjectRepository} from '@nestjs/typeorm'
import * as DataLoader from 'dataloader'
import {keyBy} from 'lodash'
import {Repository} from 'typeorm'

export interface IDataService<T> {
  readonly repository: Repository<T>
  load: (id: string | number) => Promise<T>
  loadMany: (ids: Array<string | number>) => Promise<T[]>
}

type Constructor<I> = new (...args: any[]) => I // Main Point

export function DataService<T>(entity: Constructor<T>): Type<IDataService<T>> {
  class DataServiceHost implements IDataService<T> {
    @InjectRepository(entity) public readonly repository: Repository<T>

    private get primaryColumnName(): string {
      return this.repository.metadata.primaryColumns[0]?.propertyName
    }

    private loader: DataLoader<number | string, T> = new DataLoader(async ids => {
      const entities = await this.repository.findByIds(ids as any[])
      const entitiesKeyed = keyBy(entities, this.primaryColumnName)
      return ids.map(id => entitiesKeyed[id])
    })

    public async load(id: string | number): Promise<T> {
      return this.loader.load(id)
    }

    public async loadMany(ids: Array<string | number>): Promise<T[]> {
      return this.loadMany(ids)
    }
  }
  return DataServiceHost
}

Not you can extend you services with this as explained by @BrunnerLivio here #187 (comment)

This is very nice. Can avoid a lot of boilerplate code.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Nestjs How to extend service from Generic - Stack Overflow
You need to inject repository inside constructor, so: export function DataService<T>(entity: Constructor<T>): Type<IDataService<T>> { class ...
Read more >
Implementing a Generic Repository Pattern Using NestJS
The code for AbstractRepository class is given below: You can add as many functionalities as you need. T represent each entity.
Read more >
Best Way to Inject Repositories using TypeORM (NestJS)
Taking Class-Transformer & TypeORM in NestJS & comparing them with Laravel ... UserEntity as generic types to our base ModelRepository .
Read more >
nestjs-generic-crud - npm Package Health Analysis - Snyk
In the past month we didn't find any pull request activity or change in issues status has been detected for the GitHub repository....
Read more >
typeorm-typedi-extensions - npm
TypeScript icon, indicating that this package has built-in type ... have to create the class which extends the generic Repository<T> class ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found