Real problem
I think I found my real problem, inversify
and everything else works fine.
In the original post I omitted some part of my code because I didn't think they were causing the problem.
In my ICitiesRepo
implementation I've a method ensureDb
that makes sure to init some typeorm
properties, since this method must be async I couldn't just call it in the constructor so should call it before any CRUD operation, then I created a decorator that has the purpose to call ensureDb
before any other method in the class:
export const ensureCall = (method: string) => {
return (target: any) => {
for (const prop of Object.getOwnPropertyNames(target.prototype)) {
if (prop === method || prop === 'constructor') continue;
const originalMethod = target.prototype[prop];
if (originalMethod instanceof Function) {
target.prototype[prop] = async (...args: any[]) => {
await target.prototype[method]();
return originalMethod.apply(this, args);
};
}
}
};
};
And this is the use:
@ensureCall('ensureDb')
@injectable()
class CitiesRepo implements ICitiesRepo {
@inject('CitiesWriteRepo') private readonly repo: IWriteRepo<City>;
async ensureDb() {
await this.repo.doSomething();
// repo is undefined because I messed up with the context
}
// interface implementation
}
If I remove that decorator and just call ensureDb
before others method it works:
const container = getContainer();
const citiesRepo: ICitiesRepo = container.get('CitiesRepo');
await citiesRepo.ensureDb();
const list = await citiesRepo.getAll(); // It works
Is it possible to fix this issue or some other better way to achieve what I want to do?
Original post
I have a project with a generic repository but I'm having some problem to inject the repository object with inversifyJS. The structure is like this:
interface IWriteRepo<T> { /* interface members */ }
@injectable()
class WriteRepo<City> implements IWriteRepo<City> { /* interface implementation */ }
interface ICitiesRepo { /* interface members */ }
@injectable()
class CitiesRepo implements ICitiesRepo {
@inject('CitiesWriteRepo') private readonly repo: IWriteRepo<City>;
// interface implementation
}
interface ICitiesService { /* interface members */ }
@injeactable()
class CitiesService {
@inject('CitiesRepo') repo: ICitiesRepo;
// interface implementation
}
// binding
const container = new Container();
container.bind<IWriteRepo<City>>('CitiesWriteRepo').to(WriteRepo);
container.bind<ICitiesRepo>('CitiesRepo').to(CitiesRepo);
container.bind<ICitiesService>('CitiesService').to(CitiesService);
I'm testing the code with a node application and when I try to get the generic repository (IWriteRepo<City>
) and CitiesRepo
I don't have any problem:
const container = getContainer();
const citiesRepo: ICitiesRepo = container.get('CitiesRepo'); // OK and prop repo injected correctly
const citiesWriteRepo: IWriteRepo<City> = container.get('CitiesWriteRepo'); // OK
The problem comes when I try to get the service:
const container = getContainer();
const citiesService: ICitiesService = container.get('CitiesService');
The service is injected correctly and also repo: ICitiesRepo
but the generic "grand child" repo: IWriteRepo<City>
is undefined.
Any idea about how to fix it?
EDIT
I'm still trying to find out what is the problem. Now I tried to inject the class into the constructor and something strange happens: InversifyJS injects the dependency correctly, I assign it to the property but it's undefined when I try to use it.
interface ICitiesRepo { /* interface members */ }
@injectable()
class CitiesRepo implements ICitiesRepo {
private readonly repo: IWriteRepo<City>;
constructor(@inject('CitiesWriteRepo') repo: IWriteRepo<City>) {
console.log(repo); // result: WriteRepo {}
this.repo = repo;
console.log(this.repo); // result: WriteRepo {}
}
getAll() {
console.log(this.repo); // result: undefined
}
// interface implementation
}