inversify-binding-decorators
inversify-binding-decorators copied to clipboard
fluentProvide - example
Could you please provide a full fluentProvide example? I have this kind of issue:
import { Container, decorate, inject, injectable, interfaces as inversifyInterfaces, named } from "inversify";
import { fluentProvide, buildProviderModule } from "inversify-binding-decorators";
import "reflect-metadata";
const container = new Container();
const provideFluent = fluentProvide(container);
....
export function ProvideAsSingleton(symbol: inversifyInterfaces.ServiceIdentifier<any>): any {
return provideFluent(symbol).inSingletonScope().done(true);
}
container.load(buildProviderModule());
export { container };
The issue is at:
const provideFluent = fluentProvide(container);
the error is:
[ts]
Argument of type 'Container' is not assignable to parameter of type 'string | symbol | Newable<any> | Abstract<any>'.
Type 'Container' is not assignable to type 'Abstract<any>'.
Property 'prototype' is missing in type 'Container'.
How can I use fluent provider? thanks
same issue here
Was about to open same issue. +1million
const provideFluent = fluentProvide(container);
is broken because container
is the container instance, which is not a valid service identifier (you'd for example use class Container
for that). Your ProvideAsSingleton
function should just use the library function and it will work.
The ~~buildProviderModule
~~ container.load()
line is the what couples your decorated classes to that specific container.
Sorry, but still it seems not working. I can't inject classes in the container in any way. Perhaps I'm wrong in creating or exporting container, but it seems always empty.
Custom container: ` import { Container, inject, interfaces as inversifyInterfaces } from "inversify"; import { buildProviderModule, fluentProvide } from "inversify-binding-decorators"; import "reflect-metadata"; const container = new Container(); const provideFluent = fluentProvide(Container); container.load(buildProviderModule());
export function Provide(symbol: inversifyInterfaces.ServiceIdentifier
export function ProvideAsSingleton(identifier: inversifyInterfaces.ServiceIdentifier
export function Inject(symbol: inversifyInterfaces.ServiceIdentifier
export { container }; `
Then I provide a class:
@ProvideAsSingleton(Application) export class Application { ... }
and then I try to get it:
container.get<Application>(Application).init()
When I try to get the Application instance from container, the container has its _bindingDictionary map empty, and an error occurs:
No matching bindings found for serviceIdentifier: Application
So...what I'm doing wrong? thanks!
I think container.load()
should be called when the decorators have already run (e.g. when importing from './App.ts'). The following code runs. Hope this helps
import { Container } from 'inversify';
import {
buildProviderModule,
fluentProvide,
} from 'inversify-binding-decorators';
import 'reflect-metadata';
type ArgTypes<Fn extends Function> = Fn extends (...args: infer A) => any
? A
: never;
type Identifier = ArgTypes<typeof fluentProvide>[0];
export function ProvideAsSingleton(identifier: Identifier): any {
return fluentProvide(identifier)
.inSingletonScope()
.done(true);
}
@ProvideAsSingleton(Application)
export class Application {
init() {
console.log('app init');
}
}
const container = new Container();
container.load(buildProviderModule());
console.assert(container.isBound(Application), 'Application not registered');
const app = container.get(Application);
console.assert(app != null, 'Application invalid');
app.init();
thanks for your reply, but I still have issue about this.
In order to make it working, I have to import all classes that need to register to the container before call
container.load(buildProviderModule());
and this is a different behaviuor compared with the old makeFluentProvideDecorator.
For example, if I want to register controllers or middleware in express in this way:
useExpressServer(exp, { controllers: [
${mainPath}/controllers/{.js,.ts}], defaultErrorHandler: false, middlewares: [
${mainPath}/middlewares/{.js,.ts}], routePrefix:
${serviceContext}/api});
I get this kind of error:
No matching bindings found for serviceIdentifier: HelloWorldController at _validateActiveBindingCount (...\node_modules\inversify\lib\planning\planner.js:62:23) at _getActiveBindings (...\node_modules\inversify\lib\planning\planner.js:48:5) at _createSubRequests (...node_modules\inversify\lib\planning\planner.js:85:26) at Object.plan (...\node_modules\inversify\lib\planning\planner.js:136:9) at ...\node_modules\inversify\lib\container\container.js:317:37 at Container._get (...\node_modules\inversify\lib\container\container.js:310:44) at Container.get (...\node_modules\inversify\lib\container\container.js:230:21) at Object.getFromContainer (....\node_modules\routing-controllers\container.js:37:42) at ControllerMetadata.get [as instance] (...\node_modules\routing-controllers\metadata\ControllerMetadata.js:24:32) at ActionMetadata.callMethod (....\node_modules\routing-controllers\metadata\ActionMetadata.js:107:58)
So..how can I fix this scenario?
thanks
The files need to be required at some point before that. If the file with your class in it isn't evaluated, the class does not exist as far as javascript is concerned, and it isn't decorated so inversify has no clue either. I don't know how this worked with the old behavior; I wasn't using it then. If you group your controllers and middlewares in containers you only have to require those, the rest comes with it.
This works for "inversify": "^5.1.1"
import "reflect-metadata";
import { autoProvide, fluentProvide, provide, buildProviderModule } from "inversify-binding-decorators";
import { Container, interfaces, inject } from "inversify";
const iocContainer = new Container();
const provideNamed = (identifier: string | symbol | interfaces.Newable<any> | interfaces.Abstract<any>, name: string) => {
console.log(identifier);
return fluentProvide(identifier).whenTargetNamed(name).done();
};
const provideSingleton = (identifier: string | symbol | interfaces.Newable<any> | interfaces.Abstract<any>) => {
console.log(`Register`, identifier);
return fluentProvide(identifier).inSingletonScope().done();
};
export { iocContainer, autoProvide, provide, provideSingleton, provideNamed, inject, buildProviderModule };
I got same issue that container is empty even after loading provider module from inversify-binding-decorators
.
When putting all in 1 ts file, it works. Otherwise, it does not work.
- type.ts
export let TYPE = {
Weapon : "Weapon",
Ninja: "Ninja"
}
- weapon.ts
export interface Weapon {
hit(): string;
}
- katana.ts
import {fluentProvide} from "inversify-binding-decorators";
import {TYPE} from "./type";
import {Weapon} from "./weapon";
import "reflect-metadata"
@fluentProvide(TYPE.Weapon).whenTargetTagged("throwable", true).done()
export class Katana implements Weapon {
public hit() {
return "cut!";
}
}
- ioc.ts
import { Container} from "inversify";
import "reflect-metadata";
import {buildProviderModule} from "inversify-binding-decorators";
import {TYPE} from "./type";
const container = new Container();
container.load(buildProviderModule());
container.isBoundTagged(TYPE.Weapon, "throwable", true);
export {
container
}
- test.ts
import {Weapon} from "./sample/weapon";
import {container} from "./sample/ioc";
import {TYPE} from "./sample/type";
describe("Typescript usage suite", () => {
it("should be able to execute a test", () => {
const katana: Weapon = container.getTagged<Weapon>(TYPE.Weapon, "throwable", true);
katana.hit();
});
});
- Error log:
1) Typescript usage suite
should be able to execute a test:
Error: No matching bindings found for serviceIdentifier: Weapon
Weapon - tagged: { key:throwable, value: true }
at _validateActiveBindingCount (node_modules/inversify/src/planning/planner.ts:113:15)
at _getActiveBindings (node_modules/inversify/src/planning/planner.ts:91:3)
at _createSubRequests (node_modules/inversify/src/planning/planner.ts:146:22)
at plan (node_modules/inversify/src/planning/planner.ts:240:5)
at /Users/tando/projects/mocha-examples/packages/typescript/node_modules/inversify/src/container/container.ts:623:25
at Container._get (node_modules/inversify/src/container/container.ts:574:37)
at Container._getButThrowIfAsync (node_modules/inversify/src/container/container.ts:580:25)
at Container.getTagged (node_modules/inversify/src/container/container.ts:337:17)
at Context.<anonymous> (src/index.spec.ts:7:42)
at processImmediate (node:internal/timers:466:21)
I got same issue that container is empty even after loading provider module from
inversify-binding-decorators
. When putting all in 1 ts file, it works. Otherwise, it does not work.
- type.ts
export let TYPE = { Weapon : "Weapon", Ninja: "Ninja" }
- weapon.ts
export interface Weapon { hit(): string; }
- katana.ts
import {fluentProvide} from "inversify-binding-decorators"; import {TYPE} from "./type"; import {Weapon} from "./weapon"; import "reflect-metadata" @fluentProvide(TYPE.Weapon).whenTargetTagged("throwable", true).done() export class Katana implements Weapon { public hit() { return "cut!"; } }
- ioc.ts
import { Container} from "inversify"; import "reflect-metadata"; import {buildProviderModule} from "inversify-binding-decorators"; import {TYPE} from "./type"; const container = new Container(); container.load(buildProviderModule()); container.isBoundTagged(TYPE.Weapon, "throwable", true); export { container }
- test.ts
import {Weapon} from "./sample/weapon"; import {container} from "./sample/ioc"; import {TYPE} from "./sample/type"; describe("Typescript usage suite", () => { it("should be able to execute a test", () => { const katana: Weapon = container.getTagged<Weapon>(TYPE.Weapon, "throwable", true); katana.hit(); }); });
- Error log:
1) Typescript usage suite should be able to execute a test: Error: No matching bindings found for serviceIdentifier: Weapon Weapon - tagged: { key:throwable, value: true } at _validateActiveBindingCount (node_modules/inversify/src/planning/planner.ts:113:15) at _getActiveBindings (node_modules/inversify/src/planning/planner.ts:91:3) at _createSubRequests (node_modules/inversify/src/planning/planner.ts:146:22) at plan (node_modules/inversify/src/planning/planner.ts:240:5) at /Users/tando/projects/mocha-examples/packages/typescript/node_modules/inversify/src/container/container.ts:623:25 at Container._get (node_modules/inversify/src/container/container.ts:574:37) at Container._getButThrowIfAsync (node_modules/inversify/src/container/container.ts:580:25) at Container.getTagged (node_modules/inversify/src/container/container.ts:337:17) at Context.<anonymous> (src/index.spec.ts:7:42) at processImmediate (node:internal/timers:466:21)
Did you find a workaround for this ? Thanks.
Edit : I put this here, I don't know if it will help someone but the problem I had was just a problem of module imports. I start working again with node.js and javascript in general and I completely forgot about import order. So when you call buildProviderModule() be sure to import all the injectable entities beforehand. In my case I created a loader import file which is in charge for loading everything before the call.
You can find an exemple here : https://github.com/inversify/inversify-express-example/tree/master/BindingDecorators. Be careful to respect the import "path_to_file" syntax so that Typescript understands you want to force import the module without using it right now.