Cannot read properties of undefined (reading '_userService') when using inversifyJS inject

304 Views Asked by At

I'am trying to implement a DI but seems that I'm missing some concepts of Inversify. Do I need to implement the "get" method for "user.controller" and "bind" it to the routes function?

Complete code repo

Error when I try to GET /users:

TypeError: Cannot read properties of undefined (reading '_userService')
    at /inversify-di-test/src/modules/user/user.controller.ts

index.ts

import AppBootstrap from './bin/bootstrap';
const app = new AppBootstrap().app;
export default app;

bootstrap.ts

export default class AppBootstrap {
    public app: express.Application = express();
    private appRoutes: Routes;

    constructor() {
        this.appRoutes = new DiContainer().container.resolve<Routes>(Routes);
        this.init();
    }

    private async init() {
        this.setRoutes();
        //... await this.connectDatabases();
        this.setApp();
    }

    private setRoutes() {
        const router = express.Router();

        this.appRoutes.routes(router);

        this.app.use('/api', router);
    }

    private setApp() {
        this.app.set('port', config.port);

        this.app.listen(config.port, async () => {
            console.log(`App listening on port: ${config.port}`);
        });
    }
}

inversify.config.ts

export class DiContainer {
    public container: Container;

    constructor() {
        this.configure();
    }

    public configure() {
        this.container = new Container({
            skipBaseClassChecks: true,
        });

        this.container.load(new UserModule());
    }
}

user.module.ts

export class UserModule extends ContainerModule {
    public constructor() {
        super((bind) => {
            bind<UserRouter>(UserRouter).toSelf();
            bind<IUserRepository>(USER_TYPES.IUserRepository).to(UserRepository);
            bind<UserRepository>(UserRepository).toSelf();
            bind<UserController>(UserController).toSelf();
            bind<UserService>(UserService).toSelf();
        });
    }
}

user.controller.ts

@injectable()
export class UserController {
    private _userService: UserService;

    constructor(@inject(UserService) private readonly userService: UserService) {
        this._userService = this.userService;
    }
    public async getAll(req: Request, res: Response): Promise<User[]> {
        return this._userService.getAll();
    }
}

user.repository.ts

@injectable()
export class UserRepository implements IUserRepository {
    public async getAll(): Promise<User[]> {
        return await User.find({});
    }
}

user.routes.ts

@injectable()
export class UserRouter {
    private _controller: UserController;

    public constructor(@inject(UserController) private readonly controller: UserController) {
        this._controller = this.controller;
    }

    public routes(router: express.Router): express.Router {
        router
            .route('/users')
            .get(mw.isAllowed([SUPERADMIN]), catchErrors(this._controller.getAll));

        return router;
    }
}

user.service.ts

@injectable()
export class UserService {
    private _userRepository: UserRepository;

    public constructor(@inject(UserRepository) private readonly userRepository: UserRepository) {
        this._userRepository = this.userRepository;
    }

    async getAll(): Promise<User[]> {
        return this._userRepository.getAll();
    }
}

routes/index.ts

@injectable()
export class Routes {
    constructor(public userRouter: UserRouter) {}

    public routes(router: express.Router) {
        this.userRouter.routes(router);
    }
}

Thank you in advance!

1

There are 1 best solutions below

0
Christian Onwe On

Encountered the same issue and apparently my implementation was all-through okay I was getting error for defined TYPES.

Looking at your implementation I can't get a proper view of where USER_TYPES is defined and used here

bind<IUserRepository>(USER_TYPES.IUserRepository).to(UserRepository);

Extracting all defined types i.e USER_TYPES to a separate file and import to use in user-module worked for me.

An Issue related to this was opened here.