tsfunq
TypeScript icon, indicating that this package has built-in type declarations

1.2.5 • Public • Published

TSFunq

Funq Dependency injection container port for TypeScript

Installation

You can get the latest release and the type definitions using npm:

npm install tsfunq --save

Create Dependencies

interface IDeveloper {
    code(): string;
}
 
class TypeScriptDeveloper implements IDeveloper {
    public code(): string {
        return "TypeScript";
    }
}
 
class Person {
    constructor(private developerRole: IDeveloper) {
    }
}

Create the container and register a dependency

import * as TSFunq from "tsfunq";
 
let container = new TSFunq.Container(); 
 
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper());

Resolve a dependency

let resolved = container.resolve(TypeScriptDeveloper);

Register and resolve a dependency using a key

let developer : IDeveloper;
let container = new TSFunq.Container(); 
 
container.register("TypeScriptDeveloper", c => new TypeScriptDeveloper());
developer = container.resolve("TypeScriptDeveloper");

Register and resolve a complex dependency

container.register(Person, c => {
    let developer = c.resolve(TypeScriptDeveloper);
    return new Person(developer);
});
 
let person = container.resolve(Person);

Register an instance

let resolved : IDeveloper;
let developerInstance = new TypeScriptDeveloper();
 
container.registerInstance(developerInstance);
resolved = container.resolve(TypeScriptDeveloper);

Register and resolve a named dependency

let developer : IDeveloper;
 
container.registerNamed(TypeScriptDeveloper, "foo", c => new TypeScriptDeveloper());
developer  = container.resolveNamed(TypeScriptDeveloper, "foo");
developer !== container.resolve(TypeScriptDeveloper); /// true

Try to resolve a dependency

The container will throw an exception if it will not be able to resolve a dependency.
You can use the tryResolve or tryResolvedNamed functions in order to avoid an exception:

let container = new TSFunq.Container();
let developer = container.tryResolve(TypeScriptDeveloper);
 
if (developer) {
...
}
 
let namedDeveloper = container.tryResolveNamed(TypeScriptDeveloper, "foo");
 
if (namedDeveloper) {
...
}

Register and resolve a named dependency with arguments

You can register a dependency that accepts 1 to 10 parameters

class OneArgumentClass {
    constructor(private arg1: string) {
    }
}
 
class TwoArgumentsClass {
    constructor(private arg1: string, private arg2: number) {
    }
}
 
class ThreeArgumentsClass {
    constructor(private arg1: string, private arg2: number, private arg3: Date) {
    }
}
 
class FourArgumentsClass {
    constructor(private arg1: string, private arg2: number, private arg3: Date, private arg4: any) {
    }
}
 
let container = new TSFunq.Container();
 
container.register<OneArgumentClass, string>(OneArgumentClass, (c, arg1) => new OneArgumentClass(arg1));
container.register<TwoArgumentsClass, string, number>(TwoArgumentsClass, (c, arg1, arg2) => new TwoArgumentsClass(arg1, arg2));
container.register<ThreeArgumentsClass, string, number, Date>(ThreeArgumentsClass, (c, arg1, arg2, arg3) => new ThreeArgumentsClass(arg1, arg2, arg3));
container.register<FourArgumentsClass, string, number, Date, any>(FourArgumentsClass, (c, arg1, arg2, arg3, arg4) => new FourArgumentsClass(arg1, arg2, arg3, arg4));

And resolve the dependencies using the appropriate arguments

container.resolve<OneArgumentClass, string>(OneArgumentClass, "value");
container.resolve<TwoArgumentsClass, string, number>(TwoArgumentsClass, "value", 10);
container.resolve<ThreeArgumentsClass, string, number, Date>(ThreeArgumentsClass, "value", 10, new Date());
container.resolve<FourArgumentsClass, string, number, Date, any>(FourArgumentsClass, "value", 10, new Date(), {});

Creating child containers

By default all child containers can resolve dependencies within themselves and their parent.

let resolved: TypeScriptDeveloper;
let container = new TSFunq.Container();
let child = container.createChildContainer();
 
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper());
resolved = child.resolve(TypeScriptDeveloper);
 
container.resolve(TypeScriptDeveloper); // Will raise an exception

Controlling the lifetime of an instance

The lifetime of an instance can be a singleton or per call (transient) You can control the lifetime using the TSFunq.ReuseScope enum.

enum ReuseScope {
    container = 0,
    hierarchy = 1,
    none = 2
}

By default all registrations are marked using the TSFunq.ReuseScope.container scope.

// transient
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper()).reusedWithin(TSFunq.ReuseScope.none); 
 
// singleton 
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper()).reusedWithin(TSFunq.ReuseScope.hierarchy); 
 
// singleton per container
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper()).reusedWithin(TSFunq.ReuseScope.container); 

Disposing registered instances

You can let the container to handle disposal of instances using the TSFunq.Owner enum.
You need to register a dependency using call .

enum ReuseScope {
    container = 0,
    external = 1 
}

Only instances with dispose function can be managed within the container. By default all registrations are marked using the TSFunq.Owner.container scope.

class Disposable implements TSFunq.IDisposable {
    public dispose(): void {
    }
}
 
let container = new TSFunq.Container();
 
// The container is responsible of disposing the instance
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper()).ownedBy(TSFunq.Owner.container); 
 
  // The container is not responsible of disposing the instance 
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper()).ownedBy(TSFunq.Owner.external); 

Lazy resolution

You can use the lazyResolve or lazyResolveNamed functions in order to resolve a facotry instead of an instance:

let instance : IDeveloper;
let factory : () => IDeveloper;
let container = new TSFunq.Container();
 
container.register(TypeScriptDeveloper, c => new TypeScriptDeveloper());
factory = container.lazyResolve(TypeScriptDeveloper, c => new TypeScriptDeveloper());
instance = factory();
 
container.registerNamed(TypeScriptDeveloper, "foo", c => new TypeScriptDeveloper());
factory = container.lazyResolveNamed(TypeScriptDeveloper, "foo", c => new TypeScriptDeveloper());
instance = factory();

Resolving circular dependencies

You can use the initializedBy method which run after the resolution phase.

 
class Presenter {
    public view: View;
 
    constructor(view) {
        this.view = view;
    }
}
 
class View {
    public presenter: Presenter;
}
 
let view: View;
let presenter: Presenter;
let container = new TSFunq.Container();
 
container.register(Presenter, c => new Presenter(c.resolve(View)));
container.register(View, c => new View())
         .initializedBy((c, v)  => v.presenter = c.resolve(Presenter));
 
view = container.resolve(View);
presenter = container.resolve(Presenter);

Changing the default ReuseScope/Owner

let container = new TSFunq.Container();
 
container.defaultOwner = TSFunq.Owner.external;
container.defaultReuse = TSFunq.ReuseScope.none;

License

Like Funq itself, this code is licensed under the Microsoft Public License (Ms-PL)

Copyright � 2015 Sagi Fogel

Package Sidebar

Install

npm i tsfunq

Weekly Downloads

0

Version

1.2.5

License

MS-PL

Last publish

Collaborators

  • sagi