TypeError: Cannot read property Property of undefined
General Note on my tech-stack: I have an application composed of Node.js - Express- Inversifyjs - Typescript
I have a modular structure on my express-routes on seperate files. Now when I try to inject my database-connector class on one of the routes classes, I get the error: TypeError: Cannot read property 'mongoDBClient' of undefined
Expected Behavior
My expected behaviour should be to normally inject a class into other classes, if i take into consideration that my inversify-config is setted properly.
Current Behavior
Inversify does not inject my class properly. Node detects injected class as undefined.
Steps to Reproduce (for bug)
inversify config
import 'reflect-metadata';
...
const dependencyContainer = new Container();
dependencyContainer.bind<Object>(TYPES.ENVIRONMENTAL_CONFIG).toFactory(
() => (context: interfaces.Context) => context ? CONFIG_DEVELOPMENT : CONFIG_PRODUCTION);
dependencyContainer.bind<AbstractRoutes>(TYPES.ABSTRACT_ROUTES).to(AuthRoutes).inTransientScope();
dependencyContainer.bind<AbstractRoutes>(TYPES.ABSTRACT_ROUTES).to(ApiRoutes).inTransientScope();
dependencyContainer.bind<MongoDBClient>(TYPES.MONGO_DB_CLIENT).to(MongoDBClient).inSingletonScope();
dependencyContainer.bind<CredentialHelper>(TYPES.HASH_GENERATOR).to(CredentialHelper).inSingletonScope();
dependencyContainer.bind<EmailCreator>(TYPES.EMAIL_CREATOR).to(EmailCreator).inSingletonScope();
dependencyContainer.bind<Express>(TYPES.EXPRESS).to(Express).inSingletonScope();
export default dependencyContainer;
entry-point file
import dependencyContainer from './di-config/inversify.config';
import MongoDBClient from './modules/db/mongo-db-client';
import Express from './modules/server/express';
import {TYPES} from './di-config/types';
const app = dependencyContainer.get<Express>(TYPES.EXPRESS);
(async () => app.start())();
express.file
@injectable()
export default class Express {
private static readonly PORT: any = process.env.PORT;
public app: express.Application;
public server: Http.Server;
private MongoStore = connectStore(session);
private readonly environmentalProps: any;
constructor(
@inject(TYPES.MONGO_DB_CLIENT) private mongoDBClient: MongoDBClient,
@inject(TYPES.ENVIRONMENTAL_CONFIG) private environmentFactory: Function,
@multiInject(TYPES.ABSTRACT_ROUTES) private routeManager: AbstractRoutes[]
) {
this.app = express();
this.server = new Http.Server(this.app);
this.environmentalProps = this.environmentFactory(isProduction);
}
public start() {
return this.mongoDBClient.connect()
.then(() => this.initServer())
.then(console.log);
}
private async initServer() {
this.createMiddleware();
this.assignRouteEndpoints();
return new Promise((resolve) => this.server.listen(Express.PORT, () => resolve(`Server listens on Port ${Express.PORT}`)));
}
private createMiddleware() {
...
this.app.use(express.static(joinDir(this.environmentalProps.PATH_TO_STATIC_FILES)));
}
private assignRouteEndpoints() {
this.routeManager.map((route: AbstractRoutes) => this.app.use(route.ROUTE_PARAMS, route.getRoutes()));
}
}
abstract route class
@injectable()
export default abstract class AbstractRoutes {
abstract ROUTE_PARAMS: string;
public router = express.Router();
abstract createEndpoints(): void;
public getRoutes() {
this.createEndpoints();
return this.router;
}
}
one of the route files
Error is thrown here
@injectable()
export default class AuthRoutes extends AbstractRoutes {
public ROUTE_PARAMS: string = '/auth';
constructor(@inject(TYPES.MONGO_DB_CLIENT) public mongoDBClient: MongoDBClient,
@inject(TYPES.EMAIL_CREATOR) public emailCreator: EmailCreator) {
super();
console.log(mongoDBClient); // <== is defined
console.log(mongoDBClient.connectionManager); // <== some property is undefined
}
public async checkLoggedIn(request: any, response: any) {
const sessionId = request.cookies.sid;
const uid = request.session?.user?.uid;
console.log(this.mongoDBClient); // <== crashes here
response.status(200).send({foo: 'bar'})
}
Context
The error is thrown in my route file in the checkdLogggedIn method. Normally i should be able to import the mongoDBClient class. Be aware that i import the mongoDBClient also in the parent Express class.
Your Environment
Versions:
- Node: 12.13.0
- Inversifyjs: 5.0.1
- Reflect-metadata: 0.1.13
- Typescript: 3.5.3
Stack trace
(node:7480) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'mongoDBClient' of undefined
at /home/marco/WebstormProjects/help-educate/backend/src/modules/server/routes/auth-routes.ts:24:26
at step (/home/marco/WebstormProjects/help-educate/backend/src/modules/server/routes/auth-routes.ts:58:23)
at Object.next (/home/marco/WebstormProjects/help-educate/backend/src/modules/server/routes/auth-routes.ts:39:53)
at /home/marco/WebstormProjects/help-educate/backend/src/modules/server/routes/auth-routes.ts:33:71
at new Promise (<anonymous>)
at __awaiter (/home/marco/WebstormProjects/help-educate/backend/src/modules/server/routes/auth-routes.ts:29:12)
at AuthRoutes.checkLoggedIn (/home/marco/WebstormProjects/help-educate/backend/src/modules/server/routes/auth-routes.ts:86:16)
at Layer.handle [as handle_request] (/home/marco/WebstormProjects/help-educate/backend/node_modules/express/lib/router/layer.js:95:5)
at next (/home/marco/WebstormProjects/help-educate/backend/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/home/marco/WebstormProjects/help-educate/backend/node_modules/express/lib/router/route.js:112:3)
(node:7480) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:7480) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
@MarcoLeko have you found a solution?
I had similar issue. Resolved after putting TYPES in it's own file https://github.com/inversify/InversifyJS/issues/1455