I believe I have everything set up correctly but @inject is failing to inject into the class constructor with the error: Missing required @inject or @multiInject annotation in: argument 0 in class AccountFactory despite being defined on both properties.
Using @inject on class properties works as expected. I'm only having this problem with constructor params.
This should inject the correct service
@injectable()
export class AccountFactory {
constructor(
@inject($.MongoDb.Client) private mongo: MongoClient,
@inject($.Security.PasswordHasher) private passwordHasher: IPasswordHasher,
) {}
}
I get the error: Missing required @inject or @multiInject annotation in: argument 0 in class AccountFactory.
Types are definitely correct.
Property injection works as expected:
@injectable()
export class AccountFactory {
@inject($.MongoDb.Client)
private mongo: MongoClient;
@inject($.Security.PasswordHasher)
private passwordHasher: IPasswordHasher;
}
Maybe I have configured something incorrectly, so here are the relevant files:
Inversify container definition:
export const container = new Container();
container.bind($.MongoDb.Client).toConstantValue(mongoClient);
container
.bind<IPasswordHasher>($.Security.PasswordHasher)
.to(BCryptPasswordHasher)
.inSingletonScope();
container
.bind($.MongoDb.Factory.Account)
.to(AccountFactory)
.inSingletonScope();
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"lib": ["esnext", "dom"],
"types": ["node", "jest", "reflect-metadata"],
"module": "commonjs",
"moduleResolution": "node",
"noEmit": true,
"pretty": true,
"skipLibCheck": true,
"sourceMap": true,
"allowJs": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": false,
"noUnusedLocals": false,
"strictNullChecks": true,
"forceConsistentCasingInFileNames": true,
"suppressImplicitAnyIndexErrors": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
}
.babelrc:
{
"presets": [["@babel/env"], ["@babel/typescript"]],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose": true
}
]
]
}
webpack.js:
const nodeExternals = require('webpack-node-externals');
const paths = require('./paths');
module.exports = {
mode: 'production',
entry: ['reflect-metadata', '@babel/polyfill', `${paths.src}/index.ts`],
node: {
process: false,
},
output: {
filename: 'app.js',
path: paths.build,
},
// Auto resolution
resolve: {
extensions: ['.ts', '.js'],
modules: ['node_modules', `${paths.root}/node_modules`],
},
// File and Webpack module rules
module: {
rules: [
{
test: /\.[tj]s$/,
include: paths.root,
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
],
},
externals: [
nodeExternals(), // Link modules externally as we don't need to bundle for a server
],
};
Without this, I cannot isolate units for testing without relying on Inversify rebinds.
Inversify: 5.0.1
reflext-metadata: 0.1.12
I had the same issue when I was using babel. Use tsloader instead of it!
Here you can find my config files:
https://github.com/arturgieralt/realTimeGame
so did anybody open an issue in babel project?
i faced similar issue. after importing reflect-metadata package fixed issue.
I was having a similar issue in typescript with optional properties coming after the injected properties 'missing required @inject on argument 2'. The solution for me was to explicitly assign undefined to the optional properties i.e.
constructor(@inject(TYPES.IFetch) updateProvider: IFetch,
@inject(TYPES.ILogger) logger: ILogger,
indexedDb?: IDBFactory,
...
became
constructor(@inject(TYPES.IFetch) updateProvider: IFetch,
@inject(TYPES.ILogger) logger: ILogger,
indexedDb: IDBFactory | undefined = void 0,
as a small aside, ideally the error message would state arguments[2] rather than argument 2 - as this would be more explicit that it was referring to the index.
I'm on RN 0.59.5, TS 3.4.5, Babel 7.4.4 (core, runtime & plugin-proposal-decorators). I had happily been using @injectable()as a class decorator for ages. When I introduced @inject in the parameter list of a class constructor for the first time, the 'standard' RN project recommendations for Babel & Metro config gave an Unexpected @ token error during the bundling process.
I had to switch to using react-native-typescript-transformer in my metro.config.js to resolve the problem.
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
babelTransformerPath: require.resolve('react-native-typescript-transformer')
},
};
I have set up a simple repo to illustrate this here: https://github.com/nsainaney/inversifyBabel
react-native-typescript-transformer does not seem to help. The codebase is quite simple:
// services.ts
import { Container } from 'inversify'
const kernel = new Container()
class Hello {
sayHi() {
console.log('Hi')
}
}
class There {
sayThere() {
console.log('There')
}
}
kernel.bind('hello').to(Hello)
kernel.bind('there').to(There)
// index.ts
import 'reflect-metadata'
import React from 'react'
import './services'
import { Text, View } from 'react-native';
import { injectable, inject } from 'inversify'
@injectable()
export default class App extends React.Component {
@inject('hello')
hello
@inject('there')
there
componentDidMount() {
this.hello.sayHi() // CRASHes here as hello is undefined
this.there.sayThere()
}
render() {
return (
<View>
<Text>Open up App.js to start working on your app!</Text>
</View>
);
}
}
I was finally able to fix the above. I was missing:
lazyInject instead of inject@injectable() was missing on class Hello and class ThereI've updated the codebase here: https://github.com/nsainaney/inversifyBabel. Hope this helps others out
I've added what @wyzzy suggested and it worked fine.
babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: ['module:metro-react-native-babel-preset', 'module:react-native-dotenv'],
plugins: [
['@babel/plugin-proposal-decorators', { 'legacy': true }],
]
};
};
metro.config.js
module.exports = {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
babelTransformerPath: require.resolve('react-native-typescript-transformer')
},
};
For anyone that runs into this, I solved my babel-only solution by using https://github.com/WarnerHooh/babel-plugin-parameter-decorator
@ryall I think the problem here is just that Inversify doesn't support class member injection directly in constructor. If you want to inject in the constrcutor you have to turn it into normal params by removing the visibility modifier.
Check the stackoverflow.com::babel-7-inversify-4-webpack-4-unexpected-character-on-inject answer.
babel-plugin-transform-typescript-metadata plugin helps.
Thx gods, guys made this plugin, wish it would be part of @babel/preset-typescript to work out of box.
I had the same issue using constructor injection in a react app which was created using create-react-app (react 17, react-scripts 4).
this is how the issue was fixed for me:
1- install packages
npm install --save customize-cra react-app-rewired inversify-inject-decorators
npm install --save-dev @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/preset-typescript babel-plugin-transform-typescript-metadata
(I'm not sure if all of those dev-dependencies are required though)
2- update package.json build and start scripts:
"start": "react-app-rewired start",
"build": "react-app-rewired build",
3- add a file called config-overrides.js at the same level as package.json which includes the following:
const {
override,
addBabelPlugins,
} = require("customize-cra");
module.exports = override(
...addBabelPlugins(
"babel-plugin-transform-typescript-metadata",
),
);
you can read about it here
Most helpful comment
Check the stackoverflow.com::babel-7-inversify-4-webpack-4-unexpected-character-on-inject answer.
babel-plugin-transform-typescript-metadata plugin helps.
Thx gods, guys made this plugin, wish it would be part of
@babel/preset-typescriptto work out of box.