Container

The container is that component where providers declarations are registered in order to be resolved in a second time whenever its injection are requested.

Register

import { Container, Injectable } from '@pequehq/di';

@Injectable()
class Foo {
  getPizza() {
    return 'pizza';
  }
}

const DI = new Container();

DI.set(Foo, 'Foo');

Implicit set

You can also register the providers directly within the Container constructor.

import { Container, Injectable } from '@pequehq/di';

@Injectable()
class Foo {
  getPizza() {
    return 'pizza';
  }
}

const DI = new Container({ providers: [Foo] });

Binding

Normally, the binding of the register is implicit, which means it is the provider itself (self), but in the case you want to perform an inversion of control of a provider in favor of another, you can specify an explicit binding in order to tell the container to resolve the initial provider with the bound one.

import { Container, Injectable } from '@pequehq/di';

@Injectable()
class Provider {
  test() {
    return 'pizza';
  }
}

@Injectable()
class NewProvider {
  test() {
    return 'hotdog';
  }
}

const DI = new Container();

// Register with explicit binding.
DI.set(Provider, 'Provider').to(NewProvider);
DI.set(NewProvider, 'NewProvider');

// Resolve.
DI.get('Provider').test(); // prints "hotdog";

Resolve

The resolve process takes care of resolving and injecting all the dependencies for the requested providers in order to finally deliver a working instance of it.

Recursion
Get Provider
Resolve
Look for dependencies
Return when all dependencies are resolved
Provider instance
import { Container, Injectable } from '@pequehq/di';

@Injectable()
class Foo {
  getPizza() {
    return 'pizza';
  }
}

@Injectable()
class Bar {
  constructor(private foo: Foo) {}

  test() {
    console.log(this.foo.getPizza())
  }
}

// Implicit register.
const DI = new Container({ providers: [Foo, Bar] });

// Resolve.
DI.get<Bar>('Bar').test(); // prints "pizza".

Unset

It can also be possible to unset providers from the container.

import { Container, Injectable } from '@pequehq/di';

@Injectable()
class Foo {
  getPizza() {
    return 'pizza';
  }
}

// Implicit register.
const DI = new Container({ providers: [Foo] });

// Resolve.
DI.get<Foo>('Foo').test(); // prints "pizza".

// Unset.
DI.unset('Foo').test(); // prints "pizza".

Events

Within the Container, you can intercept the init and the destroy events of the providers by defining specific callbacks inside the constructor options of the container itself.

import { Container, Injectable } from '@pequehq/di';

@Injectable()
class Provider {
  test() {
    return 'pizza';
  }
}

const DI = new Container({ 
  onInit: (name: string, instance: ProviderInstance): void => console.log(name),
  onDestroy: (name: string, instance: ProviderInstance): void => console.log(name),
});

// Register.
DI.set(Provider, 'Provider');

// Resolve.
DI.get('Provider').test(); // prints "hotdog" and triggers the onInit event.

// Unset.
DI.unset('Provider'); // it will trigger the onDestroy event.