typestack / typedi

Simple yet powerful dependency injection tool for JavaScript and TypeScript.
https://docs.typestack.community/typedi/v/develop/01-getting-started
MIT License
4.07k stars 169 forks source link

fix: Auto Inject in constructor is injecting ContainerInstance as the first parameter, and others are undefined. #1399

Closed witalobenicio closed 1 month ago

witalobenicio commented 2 months ago

Description

When injecting multiple Services inside the constructor params, the first param is a ContainerInstance, and the others are undefined.

Minimal code-snippet showcasing the problem

export class WppNotificationService {
  constructor(
    private readonly graphAPIAdapter: GraphAPIAdapter,
    private readonly openAiAdapter: OpenAiAdapter,
    private readonly fileService: FileService
  ) {
    this.fileService = fileService;
    this.openAiAdapter = openAiAdapter;
    this.graphAPIAdapter = graphAPIAdapter;
  }
}

// ...

private async handleAudioMessage(audioId: string): Promise<string> {
    console.log('THIS', this.graphAPIAdapter, this.openAiAdapter);
    //...
  }
//Log:
THIS ContainerInstance {
  services: [
    {
      id: [class OpenAiAdapter],
      type: [class OpenAiAdapter],
      factory: undefined,
      value: Symbol(EMPTY_VALUE),
      global: false,
      multiple: false,
      eager: false,
      transient: false
    },
    {
      id: [class FileService],
      type: [class FileService],
      factory: undefined,
      value: Symbol(EMPTY_VALUE),
      global: false,
      multiple: false,
      eager: false,
      transient: false
    },
    {
      id: [class WppNotificationService],
      type: [class WppNotificationService],
      factory: undefined,
      value: [WppNotificationService],
      global: false,
      multiple: false,
      eager: false,
      transient: false
    },
    {
      id: [class GraphAPIAdapter extends BaseRequesterAdapter],
      type: [class GraphAPIAdapter extends BaseRequesterAdapter],
      factory: undefined,
      value: [GraphAPIAdapter],
      global: false,
      multiple: false,
      eager: false,
      transient: false
    }
  ],
  id: 'default'
} undefined

My tsconfig:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "NodeNext",
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "moduleResolution": "Node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importsNotUsedAsValues": "remove",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "types": ["vitest/globals"]
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

Expected behavior

Each service should be an instance of the declared class.

Actual behavior

Already explained before.

jonatasdaniel commented 1 month ago

I'm having the same issue when running vitest or jest, on dev mode it works. Any ideas why?

witalobenicio commented 1 month ago

@jonatasdaniel the problem is in the metadata generator. Some typescript compilers doesn't work well with annotations. I had to move to ts-node and ts-node-dev. I was using tsc before that.

jonatasdaniel commented 1 month ago

@jonatasdaniel the problem is in the metadata generator. Some typescript compilers doesn't work well with annotations. I had to move to ts-node and ts-node-dev. I was using tsc before that.

but on my case it only happens when I run my specs with vitest or jest, on dev mode it works. I switched to inversifyjs and it works fine.

witalobenicio commented 1 month ago

You need to check what jest is using to compile your ts code.

github-actions[bot] commented 3 days ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.