Skip to main content

Deninject

A dependency injection module for Deno.

Available at Deno Land: Deninject

Contents

Injector

The main feature of this module is the Injector. This is a class that contains all the dependencies and will be resolvable based on the settings of the injection modules using some specific decorators. Let’s see a simple example:

import { Injector, Singleton, Transient } from "https://deno.land/x/deninject/mod.ts"; 

class ClassA {
    constructor() {
        console.log("buildA");
    }
}

class ClassB {
    constructor(a: ClassA) {
        console.log("buildB: ", a);
    }
}

class MyModule {
    @Singleton()
    public buildA(): ClassA {
        return new ClassA();
    }

    @Transient()
    public buildB(a: ClassA): ClassB {
        return new ClassB(a);
    }
}

const injector = new Injector(new MyModule());
const b = injector.get(ClassB);

Decorators

The decorators are responsible for making all the configuration of the dependencies. Below are their definitions:

Transient

The decorator Transient serves to mark a class or method of a module as a transient, this means that the Injector will generate a new instance for each request.

As a class:

@Transient()
class ClassA {}

As a module:

class ClassA {}

class MyModule {
    @Transient()
    public buildA(): ClassA {
        return new ClassA();
    }
}

Singleton

The decorator Singleton serves to mark a class or method of a module as a singleton, this means that the Injector will generate just one instance and store it in the cache, each request will return the same instance.

As a class:

@Singleton()
class ClassA {}

As a module:

class ClassA {}

class MyModule {
    @Singleton()
    public buildA(): ClassA {
        return new ClassA();
    }
}

Scope

The decorator Scope is used to mark a class or method of a module with a specific scope, this is useful for specific configurations for the SubInjectors. Every SubInjector works with a specific scope.

As a class:

@Transient()
@Scope("scopeA")
class ClassA {}

As a module:

class ClassA {}

class MyModule {
    @Transient()
    @Scope("scopeA")
    public buildA(): ClassA {
        return new ClassA();
    }
}

To use a SubInjector:

const subInjector = injector.sub("scopeA", new MyScopeModule());
const a = subInjector.get(ClassA);

Token

The Token decorator is used to mark a class or method of a module with a specific token, this is useful for creating different constructors for the same class.

As a class:

@Transient()
@Token("tokenA")
class ClassA {}

As a module:

class ClassA {}

class MyModule {
    @Transient()
    @Token("tokenA", true /*If you want use ignoreType*/)
    public buildA(): ClassA {
        return new ClassA();
    }
}

To retrieve an instance:

const a = injector.get(ClassA, "tokenA");

Inject

To inject a specific instance using a token.

class ClassB {
    constructor(@Inject("tokenA", true /*If you want use ignoreType*/) a: ClassA) {}
}

Dynamic Token

From time to time we need to make a more elaborate logic when instantiating classes, for this purpose DynamicToken was made, to provide more freedom in the code. Here is an example:

const tokenB = new TokenSymbol();
const tokenC = new TokenSymbol();

class ClassA {}

class ClassB extends ClassA {}

class ClassC extends ClassA {}

class MyModule {
    @Transient()
    public buildA(@DynamicToken() token: TokenSymbol): ClassA {
        if (token == tokenB) {
            return new ClassB();
        }
        else if (token == tokenC) {
            return new ClassC();
        }
        else {
            return new ClassA();
        }
    }
}

Symbols

The Symbols serve to facilitate the use of scopes and tokens in the application, it is just another option of use.

Scope Symbol

It has the same purpose as the Scope.

const scopeA = new ScopeSymbol();

@Transient()
@scopeA.apply()
class ClassA {}

Token Symbol

It has the same purpose as the Token.

const tokenA = new TokenSymbol(true /*If you want use ignoreType*/);

@Transient()
@tokenA.apply()
class ClassA {}

class ClassB {
    constructor(@tokenA.inject() a: ClassA) {}
}

Setup

This modules requires the following options to be set in the tsconfig:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}