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

"Missing required @inject or @multiInject annotation" even though it's there #1004

Closed
christianblos opened this issue Nov 25, 2018 · 28 comments

Comments

@christianblos
Copy link

Hey, I have the problem that I can't get the injects working. It always says Missing required @inject or @multiInject annotation. Event though I add this annotation it still complains (I don't have a circular dependency either).

Expected Behavior

Injection should work.

Current Behavior

I'm trying to get inversify working together with the latest create-react-app. Unfortunately no inject is working like expected. I took a really small example to reproduce this issue:

Steps to Reproduce (for bugs)

  1. create-react-app test --typescript
  2. cd test
  3. yarn add inversify reflect-metadata
  4. update tsconfig.json:
{
  "compilerOptions": {
    "target": "es5",
    "allowJs": true,
    "skipLibCheck": false,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "lib": ["es6", "dom"],
    "types": ["reflect-metadata", "node"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": [
    "src"
  ]
}
  1. replace whole content of src/index.tsx:
import {Container, injectable, inject} from 'inversify';
import 'reflect-metadata';

let container: Container = new Container();

const KatanaType: symbol = Symbol();
const ShurikenType: symbol = Symbol();
const NinjaType: symbol = Symbol();

@injectable()
class Katana {
    public hit() {
        return 'cut!';
    }
}

@injectable()
class Shuriken {
    public throw() {
        return 'hit!';
    }
}

@injectable()
class Ninja {

    public constructor(
        @inject(KatanaType) private katana: Katana,
        @inject(ShurikenType) private shuriken: Shuriken,
    ) {
    }

    public fight() {
        return this.katana.hit();
    }

    public sneak() {
        return this.shuriken.throw();
    }

}

container.bind<Katana>(KatanaType).to(Katana).inSingletonScope();
container.bind<Shuriken>(ShurikenType).to(Shuriken).inSingletonScope();
container.bind<Ninja>(NinjaType).to(Ninja).inSingletonScope();

container.get(NinjaType);
  1. run yarn start
  2. See error "Error: Missing required @Inject or @multiInject annotation in: argument 0 in class Ninja.
    ".

Environment

Node version: v10.11.0
create-react-app version: 2.1.1

package.json:

{
  "name": "test",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@types/jest": "23.3.9",
    "@types/node": "10.12.10",
    "@types/react": "16.7.7",
    "@types/react-dom": "16.0.10",
    "inversify": "^5.0.1",
    "react": "^16.6.3",
    "react-dom": "^16.6.3",
    "react-scripts": "2.1.1",
    "reflect-metadata": "^0.1.12",
    "typescript": "3.1.6"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}

I'm not sure if I have a wrong configuration somewhere or if this is a problem in create-react-app. I appreciate your help :)

@christianblos christianblos changed the title "Missing required @inject or @multiInject annotation" event though it's there "Missing required @inject or @multiInject annotation" even though it's there Nov 25, 2018
@Laazarus
Copy link

Laazarus commented Jan 2, 2019

I am having the same problem with my test project,
I cannot get the inject working with react.
I am not getting any error when I run the application but simply I get the injected service is always undefined.
Best Regards

@Roustalski
Copy link

Roustalski commented Jan 28, 2019

I created a demo repo of this for ease of reproducing.

https://github.com/Roustalski/broken-inversify

@projekt86
Copy link

@Roustalski try to remove constructor and use property injection. I create PR to your repo.

@mrdulin
Copy link

mrdulin commented Jun 6, 2019

same issue.

Missing required @Inject or @multiInject annotation in: argument 0 in class xxx

@michalzubkowicz
Copy link

I can confirm that issue, also that @projekt86 workaround works. Do you have any idea what is cause of this?

@hamstakilla
Copy link

hamstakilla commented Oct 13, 2019

if you using index.ts, and import multiple classes from it, get rid of it.
helped me.

@csr632
Copy link

csr632 commented Oct 13, 2019

maybe related to babel: #1007

@albertocorrales
Copy link

albertocorrales commented Feb 1, 2020

Do you know if there is a solution for this issue? I'm using CRA and @Inject decorator works without constructors, as @projekt86 suggested, but I would like to be able to use constructors in my typescript classes, as I was doing before installing inversify

@csr632
Copy link

csr632 commented Feb 2, 2020

@albertocorrales Use tsc or tsloader to transform ts into js if you can. If you must use babel, add this plugin.
See this for more info.

@albertocorrales
Copy link

@csr632, thanks for your answer. I would like to continue using babel, as we have some plugins there to build our bundle. However, I tried to configure the babel plugin and I'm still having the runtime error:

Error: Missing required @Inject or @multiInject annotation in: argument 0 in class Ninja.

Here I forked @Roustalski 's repo to configure babel plugin. I'm not sure if I'm missing something or it is just not working:
https://github.com/albertocorrales/broken-inversify

@kegi
Copy link

kegi commented Mar 13, 2020

Here is how I fixed it (almost fixed it) on my React (CRA) project :

I didn't wanted to eject so I added react-app-rewired (https://github.com/timarney/react-app-rewired)
I added babel-plugin-parameter-decorator (https://github.com/WarnerHooh/babel-plugin-parameter-decorator)

Here is the steps to configure react :

  1. yarn add react-app-rewired customize-cra @babel/plugin-proposal-decorators babel-plugin-parameter-decorator
  2. On package.json (scripts), replace "react-scripts" by "react-app-rewired"
  3. Create "config-overrides.js" at project root

config-overrides.js :

const { override, addDecoratorsLegacy, addBabelPlugin } = require('customize-cra')

module.exports = override(
    addDecoratorsLegacy(),
    addBabelPlugin('babel-plugin-parameter-decorator'),
)

Now, everything is working as expected and I can @Inject() in constructor.
Well... it's working only on dev react-app-rewired start but when I build it with react-app-rewired build, I have that error on the browser console : ReferenceError: inject is not defined

I feel I'm close to fix this, anyone have a clue ?

@NicholasKuchiniski
Copy link

Same issue here. I cannot get a class from a container if this class contains a constructor that receive an argument.

@cesalberca
Copy link

This is still happening, any news on what might be the problem?

@johnico
Copy link

johnico commented May 2, 2020

same issue for me in react. cra

@thomai-d
Copy link

thomai-d commented May 3, 2020

EDIT:
Ok, for more background information. Seems like this is not a bug. It's intentional by facebook:
https://create-react-app.dev/docs/can-i-use-decorators/

@Maaartinus
Copy link

@thomai-d Not exactly. With CRA, it doesn't work as it doesn't support it. With react-app-rewired, you can get decorators working. They work for me with mobx. I tried pretty everything and didn't get babel-plugin-parameter-decorator working, so for me, inversify works only for parameter-less constructors. Even the case when the injected thing is a class itself, which need no decorator doesn't work.

@johnico
Copy link

johnico commented May 5, 2020


container.bind<IApi>(TYPES.Api).toDynamicValue(() => {
        const logger = 
 container.get<ILogger>(TYPES.Logger);
  const config = container.get<IConfig>(TYPES.ConfigService);
  return new Api(config, logger);
});

After this, I can inject in the constructor and not as property.
Is it good? What is the price I pay here.
I want si only for services and not in component because component does not know the service (redux)

@adem
Copy link

adem commented May 24, 2020

Strangely enough I only have this issue when running tests. I have the same setup as @kegi and it (mostly) works fine, even building the project works fine. However, running react-app-rewired test, which runs a test that calls container.get in beforeEach yields the same error Missing required @inject or @multiInject annotation in: argument 0 in class MyClass.. Anyone else dealing with the same issue?

EDIT: I have to take that back, I get a ReferenceError: inject is not defined in my production build. I've decided to stay away from customize-cra and react-app-rewired for now, it introduced too many unknown issues. I'll try to get constructor injection to work by ejecting - will let you know when I find out anything new.

@uqee
Copy link

uqee commented Jun 10, 2020

Fixed the issue by adding more babel plugins into the test environment, my babel.config.js now looks like:

module.exports = {
  env: {
    test: {
      plugins: [
        'transform-require-context',
+        'babel-plugin-transform-typescript-metadata',
+        'babel-plugin-parameter-decorator',
      ],
    },
  },
};

Hope this helps.

@ptaferner
Copy link

if you using index.ts, and import multiple classes from it, get rid of it.
helped me.

This solved the issue for me too, but I have no idea why...

@Wintereise
Copy link

This seems to happen when you have a circular dependency issue, i.e: A requires B, B in turn requires (not via DI, just via an import) A.

https://github.com/aackerman/circular-dependency-plugin can be a handy way of chasing it down.

@omril1
Copy link

omril1 commented Jan 18, 2021

The cause of the issue is most likely a circular dependency between modules, and that's why index file with all the services/stores/modules can sometimes cause it (it depends on all the services which sometimes depend on other services.

You can play with the order of the imports in the index and it might help, but it's not guaranteed.
Webpack doesn't help detecting it out of the box, when a circular dependency happens webpack just gives you an undefined reference for the module at the top level import.

Here's a great blog post about it: https://medium.com/@catalin.luntraru/webpack-is-smart-enough-to-not-fall-for-circular-dependency-881578246aeb

In my use case I solved it by a dynamic import to the module I know I have a circular reference with.

@flolu
Copy link

flolu commented Jan 29, 2021

My problem was that I've needed to add emitDecoratorMetadata to my tsconfig.json

{
  "compilerOptions": {
    "emitDecoratorMetadata": true
  }
}

@marcosdipaolo
Copy link

marcosdipaolo commented Aug 21, 2021

Could someone inject dependencies at the constructor of a Mobx store? because I could achieve it only with property injection. Ortherwise I also get the "Missing required @Inject or @multiInject annotation"

@georgwittberger-the-nu-company

For those who want to use InversifyJS with Next.js - here is the configuration I had to adjust.

tsconfig.json (if you are using TypeScript)

Add the following properties to compilerOptions:

{
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "types": ["reflect-metadata"],
}

babel.config.js

Create Babel config file in project root directory and add this content:

module.exports = {
  presets: ['next/babel'],
  plugins: [
    'babel-plugin-transform-typescript-metadata',
    ['@babel/plugin-proposal-decorators', { legacy: true }],
  ],
}

Install the following NPM modules as dev dependencies:

  • babel-plugin-transform-typescript-metadata
  • @babel/plugin-proposal-decorators
  • @babel/core

@Mcdavid95
Copy link

For those who want to use InversifyJS with Next.js - here is the configuration I had to adjust.

tsconfig.json (if you are using TypeScript)

Add the following properties to compilerOptions:

{
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "types": ["reflect-metadata"],
}

babel.config.js

Create Babel config file in project root directory and add this content:

module.exports = {
  presets: ['next/babel'],
  plugins: [
    'babel-plugin-transform-typescript-metadata',
    ['@babel/plugin-proposal-decorators', { legacy: true }],
  ],
}

Install the following NPM modules as dev dependencies:

  • babel-plugin-transform-typescript-metadata
  • @babel/plugin-proposal-decorators
  • @babel/core

This fixed it for me. Thanks @georgwittberger-the-nu-company

@Cmrickels
Copy link

This is 9/10 times due to a circular dependency. In my case it was Service1 injecting Service2 in its constructor and Service2 injecting Service1 in its constructor.

What a poor error message though.

@notaphplover
Copy link
Member

Closing as it's a bundler config issue, unrelated to inversify.

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

No branches or pull requests