Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot read property Property of undefined #1179

Open
MarcoLeko opened this issue Dec 17, 2019 · 2 comments
Open

TypeError: Cannot read property Property of undefined #1179

MarcoLeko opened this issue Dec 17, 2019 · 2 comments

Comments

@MarcoLeko
Copy link

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.

@akisiel1
Copy link

@MarcoLeko have you found a solution?

@dmarov
Copy link

dmarov commented Jul 16, 2022

I had similar issue. Resolved after putting TYPES in it's own file #1455

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants