0.2.1 • Published 2 years ago

@inversification/ioc v0.2.1

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Inversification

A simple, lightweight, dependency-free and decorator-based IOC container for Node

Basic Usage

Register a class with the @injectable decorator:

// src/inject-me.ts

import { injectable } from 'inversification';

@injectable()
export class InjectMe {
    doThings() {
        console.log('A thing');
    }
}

Inject your service with the property decorator @inject:

// src/consumer.ts

import { inject } from 'inversification';
import { InjectMe } from './inject-me.ts';

export class Consumer {
    @inject(InjectMe.name) private service: InjectMe;

    callMe() {
        this.service.doThings();
    }
}
// src/main.ts

import { Consumer } from './consumer.ts';

const consumer = new Consumer();
consumer.callMe(); // >> 'A thing'

In this basic example you need to typecast the injected service class directly:

import { inject } from '@inversification/ioc';

export class Consumer {
    @inject('InjectMe') private service: InjectMe;
    //      ^^^^^^^^^^------- injected service's name - can be a string
    // typecast to actual service -------^^^^^^^^
}

You can find a full example here.

Auto-discover injectables

The basic usage assumes that you provide the actual class type when injecting your services. However, inversification comes with an auto-discover functionality which you can leverage to discover injectables:

// src/enums/services.ts

export enum Services {
    INJECTABLE_SERVICE = 'MyInjectableImpl',
}
// src/interfaces/my-injectable.ts

export interface MyInjectable {
    doThings(): void;
}
// src/services/my-injectable-impl.ts

import { injectable } from '@inversification/ioc';
import { MyInjectable } from '../interfaces/my-injectable';

export class MyInjectableImpl implements MyInjectable {
    doThings(): void {
        console.log('Doing things');
    }
}
// src/consumer.ts

import { inject } from '@inversification/ioc';
import { Services } from './services/services';
import { MyInjectable } from './interfaces/my-injectable';
// Note: The actual implementation does not need to be imported!

export class Consumer {
    @inject(Services.INJECTABLE_SERVICE) private service: MyInjectable;
    //                           just an interface -------^^^^^^^^^^^^
    
    run(): void {
        this.service.doThings();
    }
}
// src/main.ts

import { Inversification } from '@inversification/ioc';

// discoverInjectables() assumes that your source files live in the 'src'
// directory and will find all classes with an @injectable() decorator.
const modules = Inversification.discoverInjectables();

// You can then require these modules
modules.forEach(module => require(module));

// Consumer needs to be imported after requiring the injectables.
const { Consumer } = require('./consumer');
const consumer = new Consumer();
consumer.run();

If your source files do not live in src, you can specify an alternative directory:

// main.ts

import { Inversification } from '@inversification/ioc';
import path from 'path';

const modules = Inversification
    .discoverInjectables(path.join('packages', 'my-lib', 'sources'));

modules.forEach(module => require(module));

If you want to use the ES-style import syntax, you can wrap your importing logic in an async function:

// src/main.ts

import { Inversification } from '@inversification/ioc';

Inversification
    .discoverInjectables()
    .forEach(module => require(module));

main();

async function main() {
    const { Consumer } = await import('./consumer');
    const consumer = new Consumer();
    controller.run();
}

You can find a full example here.

Manual binding

inversification comes with a handy auto-discover functionality. However, sometimes you need to have full control over your dependency injection flow. In this case, you can configure inversification to use the InversificationStrategy.MANUAL strategy:

// src/ioc.ts

import { Inversification, InversificationStrategy } from '@inversification/ioc';

// Setting the strategy to 'manual' disables the auto-injection.
// You need to set the strategy before importing/requiring your injectables.
Inversification.setStrategy(InversificationStrategy.MANUAL);

import { Controller } from './controller';
import { OuterService } from './services/outer-service';
import { InnerServiceOne } from './services/inner-service-one';
import { InnerServiceTwo } from './services/inner-service-two';

Inversification.bind(Controller.name).to(Controller);
Inversification.bind(OuterService.name).to(OuterService);
Inversification.bind(InnerServiceOne.name).to(InnerServiceOne);
Inversification.bind(InnerServiceTwo.name).to(InnerServiceTwo);
// src/main.ts

import { Inversification } from '@inversification/ioc';
import './ioc';

import { Controller } from './controller';

const controller = Inversification
    .getService<Controller>(Controller.name);

controller.run();

You can find a full example here.