@thenja/di
v0.0.2
Published
Very simple and lean dependency injection for Typescript
Downloads
460
Readme
DI - Dependency Injection
A very simple & lean dependency injection container for Typescript.
Key features
- Decorator to Inject services
- Light weight & simple to use
- No dependencies
How to use
- Install the module
npm install @thenja/di --save
- Import and use the module
import { DI, IDIProvider } from '@thenja/di';
// our singleton service
class UtilityService {}
class User {
@DI.Inject(UtilityService)
private utilSrv: UtilityService;
}
Examples
Inject using a factory
import { DI, IDIProvider } from '@thenja/di';
let env = 'dev';
abstract class BaseStorageService {
abstract name: string;
}
class FileStorageService extends BaseStorageService {
name = 'file-storage';
}
class MemoryStorageService extends BaseStorageService {
name = 'memory-storage';
}
const storageFactory: IDIProvider = {
provide: BaseStorageService,
useFactory: () => {
if (env === 'dev') return new MemoryStorageService();
return new FileStorageService();
}
};
class MyTest {
@DI.Inject(storageFactory)
public storageSrv: BaseStorageService;
}
Inject using a different class
import { DI, IDIProvider } from '@thenja/di';
class UserModel { name = 'user'; }
class MockUserModel { name = 'mock-user'; }
const userProvider: IDIProvider = {
provide: UserModel,
useClass: MockUserModel
};
class MyTest {
@DI.Inject(userProvider)
public user: UserModel;
}
Dealing with models
Models are usually not singletons, however, we should still use dependency injection via the factory pattern to create the new model instances.
// BAD
class UserSettingsModel {}
class UserModel {
private settings: UserSettingsModel;
constructor() {
// makes it hard to mock settings, we should be using dependency injection
this.settings = new UserSettingsModel();
}
}
// BETTER
class UserSettingsModel {}
class UserModel {
constructor(private settings: UserSettingsModel) {}
}
class UserModelFactory {
create(): UserModel {
return new UserModel(new UserSettingsModel());
}
}
class UserService {
@DI.Inject(UserModelFactory)
private userModelFactory: UserModelFactory;
getUser(): UserModel {
// we can now mock the UserModelFactory
return this.userModelFactory.create();
}
}
Methods / API
@DI.Inject(service: any|IDIProvider)
Inject a singleton service into a class. You can either pass in a class object, or a IDIProvider object (see examples above).
@DI.override(service: any|IDIProvider, dependencyInstance: any)
Override a service. Useful for mocking services.
@DI.getService(service: any|IDIProvider): any
Get the service instance that is stored inside the dependency container.
@DI.clear()
Clear the dependency container.
@DI.getContainer(): { [key: string]: any }
Get the dependency container. Basically, the container is a json object with the key being the name of the service (randomly generated) and the value being the instance of the service.
@DI.getContainerName(service: any|IDIProvider): string
Get the name used in the dependency container for a particular service.
Development
npm run init
- Setup the app for development (run once after cloning)
npm run dev
- Run this command when you want to work on this app. It will
compile typescript, run tests and watch for file changes.
Distribution
npm run build -- -v <version>
- Create a distribution build of the app.
-v (version) - [Optional] Either "patch", "minor" or "major". Increase the version number in the package.json file.
The build command creates a /compiled directory which has all the javascript compiled code and typescript definitions. As well, a /dist directory is created that contains a minified javascript file.
Testing
Tests are automatically ran when you do a build.
npm run test
- Run the tests. The tests will be ran in a nodejs environment.
You can run the tests in a browser environment by opening the file
/spec/in-browser/SpecRunner.html.
License
MIT © Nathan Anderson