Translated the InversifyJS English document with jeff-Tian, ღ(´ ᴗ · ‘)

Warehouse address: github.com/NeoYo/inver… Welcome fork or start

InversifyJS is a powerful and lightweight inversion of control container for JavaScript and Node.js applications written in TypeScript.

InversifyJS: github.com/inversify/I…

InversifyJS official website: inversify.io

InversifyJS Chinese document: www.inversify.cn

Introduction to the

InversifyJS is a lightweight (4KB) inversion of control container (IoC) that can be used to write TypeScript and JavaScript applications. It uses class constructors to define and inject its dependencies. The InversifyJS API is user-friendly and encourages the application of OOP and IoC best practices.

Why InversifyJS?

JavaScript now supports object-oriented programming, class-based inheritance. These are nice features but they are actually dangerous. We need a good object-oriented design (SOLID, Composite Reuse, etc.) to protect us from these threats. However, object-oriented design is complex, so we created InversifyJS.

InversifyJS is a tool that helps JavaScript developers write excellent object-oriented design code.

The target

InversifyJS has four main goals:

  1. Allows JavaScript developers to write code that follows SOLID principles.

  2. Promote and encourage adherence to best object-oriented programming and dependency injection practices.

  3. As little runtime overhead as possible.

  4. Provide artistic programming experience and ecology.

The evaluation of

Nate Kohari – Author of Ninject

“Nice work! I’ve taken a couple shots at creating DI frameworks for JavaScript and TypeScript, but the lack of RTTI really hinders things.The ES7 metadata gets us part of the way there (as you’ve discovered). Keep up the great work!”

Author of Michel Weststrate – MobX

Dependency injection like InversifyJS works nicely

Companies that use InversifyJS

The installation

You can use NPM to get the latest version and type definitions:

$ npm install inversify reflect-metadata --save
Copy the code

The Inversify NPM package already contains type definitions for InversifyJS

Warning: Important! InversifyJS requires TypeScript versions >= 2.0 as well as experimentalDecorators, emitDecoratorMetadata, The types and lib compilerOptions configuration in tsconfig.json is as follows:

{
    "compilerOptions": {
        "target": "es5"."lib": ["es6"]."types": ["reflect-metadata"]."module": "commonjs"."moduleResolution": "node"."experimentalDecorators": true."emitDecoratorMetadata": true}}Copy the code

Inversifyjs requires a modern JavaScript engine that supports the following features

  • Reflect metadata
  • Map
  • Promise (Only required if using provider injection)
  • Proxy (Only required if using activation handlers)

If your runtime environment does not support these features, you may need to import Shim or Polyfill

: Warning: Reflect-Metadata Polyfill should only be imported once throughout your application because the Reflect object needs to be a global singleton. More details can be found here.

Look at polyfills, the development environment in the Wiki, and learn from basic examples.

Based on some

Let’s take a look at the basic usage and API of InversifyJS:

Step 1: Declare the interface and type

Our goal is to write code that follows the dependency inversion principle.

This means that we should “rely on abstractions rather than concrete implementations”.

Let’s first declare some interfaces (abstractions).

// file interfaces.ts

interface Warrior {
    fight(): string;
    sneak(): string;
}

interface Weapon {
    hit(): string;
}

interface ThrowableWeapon {
    throw() :string;
}
Copy the code

Inversifyjs requires type tags as identifiers at run time. Next, you’ll use Symbol as the identifier, or you can use classes or strings.

// file types.ts

const TYPES = {
    Warrior: Symbol.for("Warrior"),
    Weapon: Symbol.for("Weapon"),
    ThrowableWeapon: Symbol.for("ThrowableWeapon")};export { TYPES };

Copy the code

Caution: Symbol is recommended, but InversifyJS also supports using classes and string literals (see the features section for more information).

Step 2: Use@injectable@injectDecorators declare dependencies

Let’s declare some classes that implement the interface we just declared. They all need to be annotated with the @ Injectable decorator.

When a class depends on an interface, we also need to use the @Inject decorator to define the interface identity available at runtime. In this case, we will use symbols such as symbol.for (“Weapon”) and symbol.for (“ThrowableWeapon”) as the identifiers for the runtime.

// file entities.ts

import { injectable, inject } from "inversify";
import "reflect-metadata";
import { Weapon, ThrowableWeapon, Warrior } from "./interfaces"
import { TYPES } from "./types";

@injectable(a)class Katana implements Weapon {
    public hit() {
        return "cut!"; }}@injectable(a)class Shuriken implements ThrowableWeapon {
    public throw() {
        return "hit!"; }}@injectable(a)class Ninja implements Warrior {

    private _katana: Weapon;
    private _shuriken: ThrowableWeapon;

    public constructor(
	    @inject(TYPES.Weapon) katana: Weapon,
	    @inject(TYPES.ThrowableWeapon) shuriken: ThrowableWeapon
    ) {
        this._katana = katana;
        this._shuriken = shuriken;
    }

    public fight() { return this._katana.hit(); }
    public sneak() { return this._shuriken.throw(); }}export { Ninja, Katana, Shuriken };
Copy the code

If you prefer to use property injection instead of constructor injection, you don’t have to declare a constructor for your class:

@injectable(a)class Ninja implements Warrior {
    @inject(TYPES.Weapon) private _katana: Weapon;
    @inject(TYPES.ThrowableWeapon) private _shuriken: ThrowableWeapon;
    public fight() { return this._katana.hit(); }
    public sneak() { return this._shuriken.throw(); }}Copy the code

Step 3: Create and configure containers

It is recommended to create and configure containers in a file named inversify.config.ts. That’s the only place where there’s coupling. Classes in the rest of your project should not contain references to other classes.

// file inversify.config.ts

import { Container } from "inversify";
import { TYPES } from "./types";
import { Warrior, Weapon, ThrowableWeapon } from "./interfaces";
import { Ninja, Katana, Shuriken } from "./entities";

const myContainer = new Container();
myContainer.bind<Warrior>(TYPES.Warrior).to(Ninja);
myContainer.bind<Weapon>(TYPES.Weapon).to(Katana);
myContainer.bind<ThrowableWeapon>(TYPES.ThrowableWeapon).to(Shuriken);

export { myContainer };
Copy the code

Step 4: Resolve dependencies

You can get the dependency from the Container using the method get

. Remember that you should resolve dependencies in the root structure, as close as possible to the entry point of the application, to avoid server localization antipatterns.

import { myContainer } from "./inversify.config";
import { TYPES } from "./types";
import { Warrior } from "./interfaces";

const ninja = myContainer.get<Warrior>(TYPES.Warrior);

expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true
Copy the code

As we saw Katana and Shuriken were successfully parsed and injected into Ninja.

InversifyJS supports ES5 and ES6 and can be used without TypeScript. Go to JavaScript examples to learn more

InversifyJS features and APIS

Let’s take a look at the features of InversifyJS!

Please consult the wiki for more details.

  • Class as identifier
  • Symbol as a Symbol
  • Container API
  • Declare container module
  • Container snapshot
  • Control the life cycle of dependencies
  • Declare optional dependencies
  • Inject constants or dynamic values
  • Inject the constructor of the class
  • Into the factory
  • Automatic factory
  • Injection provider (asynchronous factory)
  • Activate the handle
  • Constructor rear decorator
  • The middleware
  • Multiple injection
  • Label the binding
  • Create your own label decorator
  • Naming binding
  • The default target
  • Support for hierarchical dependency injection systems
  • Context binding and @targetName
  • Properties into
  • Circular dependencies
  • inheritance

Please consult the wiki for more details.

ecological

In order to provide an artistic development experience, we also strive to:

  • Middleware plug-in
  • The development tools
  • example

Check out the Ecology Wiki page to learn more.

Support

If you have any problems, we are happy to help. You can use the problems page to report problems.

If you would like to share your thoughts with the development team or join us, you can join the discussion forum. You can also check out the wiki to learn more about InversifyJS.

Acknowledgements

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.

License

License under the MIT License (MIT)

Copyright © 2015-2017 Remo H. Jansen

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.

IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.