Announcing InversifyJS 2.0.0 Release Candidate ?

Learn what’s new in InversifyJS 2.0.0 and what can you expect to see in the future of this powerful lightweight IoC container for JavaScript and Node.js apps powered by TypeScript

687474703a2f2f692e696d6775722e636f6d2f303473443733522e6a7067.jpg

As many of the readers of this blog already know, over the past year and a half we have been working on InversifyJS.

InversifyJS is a powerful lightweight IoC container for JavaScript and Node.js written in TypeScript.

Last march we announced that we were working on InversifyJS 2.0. Today we are happy to announce that InversifyJS 2.0 release candidate is available on npm.

In this post we are going to learn about the following:

Let’s get started!

 Setting up InversifyJS 2.0 with TypeScript

$ npm install inversify@2.0.0-beta.5 reflect-metadata --save
$ npm install inversify-dts --save-dev
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

Please refer to the InversifyJS installation guide for more details.

 The InversifyJS 2.0 API

The InversifyJS API has changed a lot over the last couple of months, so let’s take a look to the final syntax.

The following example is not the most basic example but it is a good example to showcase the power of InversifyJS.

The first thing we need to do is to import reflect-metadata, the injectable, named and inject decorators and the Kernel class from ImversifyJS and the required TypeScript type definitions:

/// <reference path="./node_modules/inversify-dts/inversify/inversify.d.ts" />
/// <reference path="./node_modules/reflect-metadata/reflect-metadata.d.ts" />

import { Kernel, injectable, inject, named } from "inversify";
import "reflect-metadata";

Then we can declare some interfaces:

interface Warrior {
    fight(): string;
}

interface Weapon{
    use(): string;
}

interface Battlefield{
    warrior1: Warrior;
    warrior2: Warrior;
}

We are also going to declare some Symbols and tags. These are constants that are used as IDs and metadata. Because the constants are strings literals it is better to declare them just once in the whole application and that is what we are doing here:

let TYPES = {
    Warrior: Symbol("Warrior"),
    Weapon: Symbol("Weapon"),
    Battlefield: Symbol("Battlefield")
};

let TAGS = {
    ninja: "ninja",
    samurai: "samurai"
};

We can then implement the interfaces. In this case we are going to declare two implementations of the Weapon interface:

@injectable()
class Katana implements Weapon {
    public use() {
        return "Used Katana!";
    }
}

@injectable()
class Shuriken implements Weapon {
    public use() {
        return "Used Shuriken!";
    }
}

One implementation of the Warrior interface:

@injectable()
class Warrior implements Warrior  {

    private _weapon: Weapon;

    public constructor(
        @inject(TYPES.Weapon) weapon: Weapon
    ) {
        this._weapon = weapon;
    }

    public fight() { return this._weapon.use(); };

}

One implementation of the Battlefield interface:

@injectable()
class Battlefield implements Battlefield {

    public warrior1: Warrior;
    public warrior2: Warrior;

    public constructor(
         @inject(TYPES.Warrior) @named(TAGS.ninja) warrior1: Warrior,
         @inject(TYPES.Warrior) @named(TAGS.samurai) warrior2: Warrior
    ) {
        this.warrior1 = warrior1;
        this.warrior2 = warrior2;
    }

}

We need to annotate all these classes with the injectable decorator and if the class has dependencies we also need to use the inject decorator to declare the type of the dependency.

Now that our entities are ready, we can create an instance of the InversifyJS kernel.

We then need to declare some bindings. A binding is a map between an interface and an implementation of that type. A binding can also have constraints. Constraints allow us to limit the binding to a context. In this case we are going to declare the following constraints:

var kernel = new Kernel();

kernel.bind<Weapon>(TYPES.Weapon)
      .to(Katana)
      .whenParentNamed(TAGS.samurai);

kernel.bind<Weapon>(TYPES.Weapon)
      .to(Shuriken)
      .whenParentNamed(TAGS.ninja);

kernel.bind<Warrior>(TYPES.Warrior)
      .to(Warrior);

kernel.bind<Battlefield>(TYPES.Battlefield)
      .to(Battlefield);

At this point we can request an instance of Battlefield and the InversifyJS Kernel will be able to resolve

let battlefield = kernel.get<Battlefield>(TYPES.Battlefield);

battlefield.warrior1.fight(); // > "Used Shuriken!"
battlefield.warrior2.fight(); // > "Used Katana!"

 The InversifyJS 2.0 features

InversifyJS 2.0 is really powerful and its list of features is very extensive:

You can visit GitHub or www.inversify.io to learn more about these features.

 The InversifyJS ecosystem

I believe that InversifyJS is great but we think that being great is not enough. I want to provide the community with an awesome library and awesome ecosystem of extensions and development tools. Let’s take a look to some of them.

 The inversify-binding-decorators project

There is an alternative binding syntax that uses decorators. Instead of writing:

import { injectable, Kernel } from "inversify";
import "reflect-metadata";

@injectable()
class Katana implements Weapon {
    public hit() {
        return "cut!";
    }
}

@injectable()
class Shuriken implements ThrowableWeapon {
    public throw() {
        return "hit!";
    }
}

var kernel = new Kernel();
kernel.bind<Weapon>("Weapon").to(Katana);
kernel.bind<ThrowableWeapon>("ThrowableWeapon").to(Shuriken);

We can write the following:

import { injectable, Kernel } from "inversify";
import makeProvideDecorator from "inversify-binding-decorators";
import "reflect-metadata";

var kernel = new Kernel();
let provide = makeProvideDecorator(kernel);

@provide("Weapon")
class Katana implements Weapon {
    public hit() {
        return "cut!";
    }
}

@provide("ThrowableWeapon")
class Shuriken implements ThrowableWeapon {
    public throw() {
        return "hit!";
    }
}

The inversify-binding-decorators project also allows us to declare contextual constraints using decorators:

@provide("Weapon").whenTargetTagged("throwable", false).done();
class Katana implements Weapon {
    public hit() {
        return "cut!";
    }
}

You can learn more about this project on GitHub.

 The inversify-logger-middleware project

This project provides you with a configurable console logging middleware:

687474703a2f2f692e696d6775722e636f6d2f6946416f67726f2e706e67.png

This middle ware can help you to identify issues and to have a better understanding of the object composition.

You can learn more about this project on GitHub.

 The inversify-devtools project [Coming Soon]

This project provides InversifyJS developers with a browser extension that helps you to work with InversifyJS in front-end applications.

1.png

2.png

3.png

You can learn more about this project on GitHub.

 The inversify-express-utils project

This projects provides some utilities for the development of Node.js application with Express.

Untitled.png

You can learn more at GiiHub.

 Other projects

The list of projects does not end here! Check out the InversifyJS ecosystem page on GitHub to learn about other projects.

 The InversifyJS community

The InversifyJS community is still relatively small but it has been growing steadily over the last few months. There are other libraries and frameworks depending on it already.

Untitled.png

Thanks a lot to all the contributors, all the developers out there using InversifyJS and all those that help us to spread the word by sharing content about InversifyJS online. Without your feedback and support this project would not be possible.

 The future of InversifyJS

Now that the core library is stable we will focus on improving documentations and examples. We will also work in development tools so you guys can enjoy a state of the art development experience.

There are two major features that we are planning to try to implement and I believe are worth mention here:

The best way to be updated is to check the issues page on GitHub.

 Summary

I’ve been working on InversifyJS for over a year and it has been an amazing experience.

I believe that InversifyJS a lot of potential and we are just getting started. I hope that the community will continue to grow and I can’t wait to see what amazing stuff the people will build with it.

Please try InversifyJS and let us know what do you think. We want to define a road map based on the real needs of real users and the only way we can do that is if you let us know what you need and what you don’t like.

Remember that you can visit http://inversify.io/ or the GitHub repo to learn more about InversifyJS.

Please feel free to let us know your thoughts about this article with us via @OweR_ReLoaDeD, @WolkSoftwareLtd and @InversifyJS.

Don’t forget to subscribe if you don’t want to miss it out future articles!

 
36
Kudos
 
36
Kudos

Now read this

Decorators & metadata reflection in TypeScript: From Novice to Expert (Part II)

An in-depth look to the TypeScript implementation of decorators and how they make possible new exciting JavaScript features like reflection or dependency injection. This article is the second part of a series: PART I: Method decorators... Continue →