Skip to content

Lightweight dependency injection container for TypeScript with async support

License

Notifications You must be signed in to change notification settings

maca134/async-syringe

Repository files navigation

AsyncSyringe

build status npm version downloads Donate

Based on tsyringe but with support for async factories/init and does not use any global variables.

Installation

Install by npm

npm install --save @maca134/async-syringe

or install with yarn

yarn add @maca134/async-syringe

Modify your tsconfig.json to include the following settings

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

Add a polyfill for the Reflect API (examples below use reflect-metadata). You can use:

The Reflect polyfill import should only be added once, and before before DI is used:

// main.ts
import 'reflect-metadata';

// Your code here...

Examples

Working examples can be found in the root folder. Here is the code:

Simple

import 'reflect-metadata';
import { injectable, StandardKernel } from '../..';
import { inject } from '../../decorators/inject';
import { singleton } from '../../decorators/singleton';

(async () => {
	class Foo1 {}

	// indicates only 1 instances of this class will be created
	@singleton()
	class Foo2 {}

	// injectable decorator is only needed when there are constructor parameters
	@injectable()
	class Bar {
		constructor(
			public foo1: Foo1,
			public foo2: Foo2,
			@inject('value') public foobarFromValue: string,
			@inject('factory') public foobarFromFactoryValue: string,
			@inject('token') public foobarFromTokenFactoryValue: string
		) {}
	}

	const container = new StandardKernel();

	container.registerValue('value', 'foobarValue');
	container.registerFactory('factory', (kernel) => kernel.resolve('value'));
	container.registerToken('token', 'factory');

	// A token can be resolved without being registered if it is a class constructor
	console.log(await container.resolve(Bar));
	/*
	Bar {
		foo1: Foo1 {},
		foo2: Foo2 {},
		foobarFromValue: 'foobarValue',
		foobarFromFactoryValue: 'foobarValue',
		foobarFromTokenFactoryValue: 'foobarValue'
	}
	*/
})();

Class Initializing

import 'reflect-metadata';
import { injectable, StandardKernel } from '../..';

(async () => {
	// to use initialize properly the decorator needs to be typed.
	// the initialize function can be a promise
	@injectable<Bar>({ initialize: (instance) => instance.init() })
	class Bar {
		init(): Promise<any> {
			return new Promise((resolve) => setTimeout(() => resolve(), 4000));
		}
	}

	@injectable()
	class Foo {
		constructor(public bar: Bar) {}
	}

	const container = new StandardKernel();
	console.log(await container.resolve(Foo));
	/*
	...4s...
	Foo { bar: Bar {} }
	*/
})();

Factories

import 'reflect-metadata';
import { injectable, StandardKernel } from '../..';
import { autoFactory } from '../../decorators/autoFactory';
import { Factory } from '../../Factory';

(async () => {
	@injectable()
	class Foo {
		constructor(
			public bar: string,
			public foobar: number
		) {}
	}

	@injectable()
	class Bar {
		constructor(@autoFactory(Foo) public fooFactory: Factory<typeof Foo>) {}
	}

	const container = new StandardKernel();
	const bar = await container.resolve(Bar);
	console.log(await bar.fooFactory.create('bar', 1337));
	/*
	Foo { bar: 'bar', foobar: 1337 }
	*/
})();

About

Lightweight dependency injection container for TypeScript with async support

Resources

License

Stars

Watchers

Forks

Packages

No packages published