microsoft / tsyringe

Lightweight dependency injection container for JavaScript/TypeScript
MIT License
5.16k stars 173 forks source link

Cannot read property 'length' of undefined #58

Closed benoj closed 4 years ago

benoj commented 5 years ago

Describe the bug When I have a class with an empty constructor container blows up. I have a class which requires the CLASS (below).

This causes the whole container to blow up with an undefined.length issue.

 InternalDependencyContainer.prototype.resolve = function (token) { <--- token is undefined
        console.info("TOKEN", token)
        var registration = this.getRegistration(token);
        console.info("REGISTRATION", registration)
        if (!registration && isNormalToken(token)) {
            throw "Attempted to resolve unregistered dependency token: " + token.toString();
        }
        if (registration) {
            return this.resolveRegistration(registration);
        }
        return this.construct(token);
    };

To Reproduce

CLASS Causing the issue

@singleton()
export class EventService {
    private config: EventConfig
    private sns: SNS

    public constructor() {
        this.config = eventConfig
        this.sns = new SNS({
            endpoint: eventConfig.endpoint,
        })
    }

    public async publish(event: Event): Promise<void> {
        const opts: PublishInput = {
            Message: JSON.stringify(event),
            TopicArn: this.config.topicArn,
            Subject: event.type,
        }
        await this.sns.publish(opts).promise()
    }
}

ERROR:


TypeError: Cannot read property 'length' of undefined
    at InternalDependencyContainer.../../../node_modules/tsyringe/dist/esm5/dependency-container.js.InternalDependencyContainer.construct (/Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/tsyringe/dist/esm5/dependency-container.js:133:1)
    at InternalDependencyContainer.../../../node_modules/tsyringe/dist/esm5/dependency-container.js.InternalDependencyContainer.resolve (/Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/tsyringe/dist/esm5/dependency-container.js:67:1)
    at /Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/tsyringe/dist/esm5/dependency-container.js:147:1
    at Array.map (<anonymous>)
    at InternalDependencyContainer.../../../node_modules/tsyringe/dist/esm5/dependency-container.js.InternalDependencyContainer.construct (/Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/tsyringe/dist/esm5/dependency-container.js:140:1)
    at InternalDependencyContainer.../../../node_modules/tsyringe/dist/esm5/dependency-container.js.InternalDependencyContainer.resolve (/Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/tsyringe/dist/esm5/dependency-container.js:67:1)
    at Object../src/handlers/companies/listCompanyStages.ts (/Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/src/handlers/companies/listCompanyStages.ts:21:34)
    at __webpack_require__ (/Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/webpack/bootstrap:19:1)
    at /Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/webpack:/webpack/bootstrap:83:1
    at Object.<anonymous> (/Users/flowers_ben/Projects/ortus/ortus-monorepo/packages/api/client/.webpack/service/src/handlers/companies/listCompanyStages.js:87:10)
    at Module._compile (internal/modules/cjs/loader.js:738:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:749:10)
    at Module.load (internal/modules/cjs/loader.js:630:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:570:12)
    at Function.Module._load (internal/modules/cjs/loader.js:562:3)
    at Module.require (internal/modules/cjs/loader.js:667:17)
    at require (internal/modules/cjs/helpers.js:20:18)
    at Object.createHandler (/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/serverless-offline/src/functionHelper.js:215:15)
    at handler (/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/serverless-offline/src/ApiGateway.js:485:40)
    at module.exports.internals.Manager.execute (/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/@hapi/hapi/lib/toolkit.js:41:33)
    at Object.internals.handler (/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/@hapi/hapi/lib/handler.js:46:48)
    at exports.execute (/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/@hapi/hapi/lib/handler.js:31:36)
    at Request._lifecycle (/Users/flowers_ben/Projects/ortus/ortus-monorepo/node_modules/@hapi/hapi/lib/request.js:312:68)
    at processTicksAndRejections (internal/process/next_tick.js:81:5)
benoj commented 5 years ago

For now I can get around it by labelling the class with @inject("eventService") and initialising in the top level - but this isn't ideal

benoj commented 5 years ago

ping

skiptirengu commented 5 years ago

Can you provide a valid test case to reproduce this issue? Tried these two and the container seems to be able to resolve the dependencies just fine.

test("test empty constructor 1", () => {
  @singleton()
  class EventService {
    private config: object;
    private sns: object;

    public constructor() {
      this.config = {};
      this.sns = {};
    }

    public async publish(): Promise<void> {
      console.log(this.config);
      console.log(this.sns);
    }
  }

  globalContainer.resolve(EventService);
});

and

test("test empty constructor 2", () => {
  @singleton()
  class EventService {
    private config: object;
    private sns: object;

    public constructor() {
      this.config = {};
      this.sns = {};
    }

    public async publish(): Promise<void> {
      console.log(this.config);
      console.log(this.sns);
    }
  }

  @singleton()
  class MyClass {
    constructor(@inject(EventService) service: EventService) {
      console.log(service);
    }
  }

  globalContainer.resolve(MyClass);
});
A-Babin commented 5 years ago

I just encountered a similar Cannot read property 'length' error. I've narrowed it to usage of an index.ts file, but it's not clear to me why that's causing issues.

src/
    services/
        ServiceA.ts  
        ServiceB.ts
        ServiceC.ts
        index.ts
    main.ts

services/index.ts

export * from "./ServiceA" 
export * from "./ServiceB" 
export * from "./ServiceC"

ServiceA and ServiceB aren't dependent on any other services.

ServiceC.ts

//...
import { ServiceA, ServiceB } from "./"; // ⛔ Doesn't work.
//import { ServiceA } from "./ServiceA"; // ✅ 
//import { ServiceB } from "./ServiceB"; // ✅ Everything works fine.

@singleton()
export class ServiceC { 
    constructor(private a : ServiceA, private b : ServiceB) { } 
//... 
}

main.ts

// How they're imported here doesn't seem to make a difference
import { ServiceA, ServiceB, ServiceC } from "./services"; 

container.resolve(ServiceA); // ✅ 
container.resolve(ServiceC); // ⛔ Cannot read property 'length' of undefined

Logging the container in main.ts does show that ServiceC is in the registry.

Uncaught TypeError: Cannot read property 'length' of undefined
    at InternalDependencyContainer.construct (dependency-container.js:129)
    at InternalDependencyContainer.resolve (dependency-container.js:72)

EDIT: Well, I just created a reduced test case with StackBlitz, and I'm not seeing any problems with it. My project is a Chrome extension content script so that might be causing an issue or it could be webpack.

skiptirengu commented 5 years ago

I've created a webpack + typescript project to try and reproduce this bug but was unable to narrow down the issue.

If I have to guess this is probably caused by some shady webpack/babel/etc plugin.

Xapphire13 commented 4 years ago

Closing due to lack of activity

naydichev commented 2 years ago

This is still an issue. Confirmed today - replace indirect imports to direct imports and that fixed our weird bugs.

jamaltheatlantean commented 2 years ago

This is still an issue. Confirmed today - replace indirect imports to direct imports and that fixed our weird bugs.

Can you shed more light on this? I currently have this issue trying to deploy a solidity smart contract. I traced the error back to a folder in my node_module\hardhat-deploy\src\helpers.ts but still can't get rid of the error. If you could just explain what you meant by replacing indirect imports with direct one's