Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

typedi

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

typedi - npm Package Compare versions

Comparing version 0.4.3 to 0.5.0

decorators/Inject.d.ts

97

Container.d.ts

@@ -1,61 +0,84 @@

import { ParamHandler, PropertyHandler } from "./Handlers";
import { ServiceMetadata } from "./types/ServiceMetadata";
import { ObjectType } from "./types/ObjectType";
import { Handler } from "./types/Handler";
import { Token } from "./Token";
import { ServiceIdentifier } from "./types/ServiceIdentifier";
/**
* Special type that allows to use Function and to known its type as T.
*/
export declare type ConstructorFunction<T> = {
new (...args: any[]): T;
};
/**
* Service container.
*/
export declare class Container {
private static instances;
private static paramHandlers;
private static propertyHandlers;
private static registeredServices;
/**
* Registers a new constructor parameter handler.
* All registered services.
*/
static registerParamHandler(paramHandler: ParamHandler): void;
private static services;
/**
* Registers a new class property handler.
* All registered handlers.
*/
static registerPropertyHandler(propertyHandler: PropertyHandler): void;
private static handlers;
/**
* Registers a new handler.
*/
static registerHandler(handler: Handler): void;
/**
* Registers a new service.
*
* @param name Service name. Optional
* @param type Service class
* @param params Parameters to be sent to constructor on service initialization
*/
static registerService(name: string, type: Function, params?: any[]): void;
static registerService<T, K extends keyof T>(descriptor: ServiceMetadata<T, K>): void;
/**
* Retrieves the service with the specific name or given type from the service container.
* Optionally parameters can be pass in the case if instance is initialized in the container for the first time.
* Retrieves the service with given name or type from the service container.
* Optionally, parameters can be passed in case if instance is initialized in the container for the first time.
*/
static get<T>(type: ConstructorFunction<T>, params?: any[]): T;
static get<T>(name: string, params?: any[]): T;
static get<T>(type: ObjectType<T>): T;
/**
* Retrieves the service with given name or type from the service container.
* Optionally, parameters can be passed in case if instance is initialized in the container for the first time.
*/
static get<T>(id: string): T;
/**
* Retrieves the service with given name or type from the service container.
* Optionally, parameters can be passed in case if instance is initialized in the container for the first time.
*/
static get<T>(id: Token<T>): T;
/**
* Sets a value for the given type or service name in the container.
*/
static set(type: Function, value: any): void;
static set(name: string, value: any): void;
static set(type: Function, value: any): Container;
/**
* Sets a value for the given type or service name in the container.
*/
static set(name: string, value: any): Container;
/**
* Sets a value for the given type or service name in the container.
*/
static set(token: Token<any>, value: any): Container;
/**
* Provides a set of values to be saved in the container.
*/
static provide(values: {
name?: string;
type?: Function;
id: ServiceIdentifier;
value: any;
}[]): void;
/**
* Removes services with a given service identifiers (tokens or types).
*/
static remove(...ids: ServiceIdentifier[]): void;
/**
* Completely resets the container by removing all previously registered services and handlers from it.
*/
static reset(): void;
/**
* Finds registered service in the with a given service identifier.
*/
private static findService(identifier);
/**
* Initializes all parameter types for a given target service class.
*/
private static initializeParams(type, paramTypes);
/**
* Checks if given type is primitive (e.g. string, boolean, number, object).
*/
private static isTypePrimitive(param);
/**
* Applies all registered handlers on a given target class.
*/
private static applyPropertyHandlers(target);
private static findInstance(name, type);
private static findInstanceByName(name);
private static findInstanceByType(type);
private static findRegisteredService(name, type);
private static findRegisteredServiceByType(type);
private static findRegisteredServiceByName(name);
private static findParamHandler(type, index);
private static initializeParams(type, params);
private static isTypeSimple(param);
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Token_1 = require("./Token");
var ServiceNotFoundError_1 = require("./error/ServiceNotFoundError");
/**

@@ -12,74 +15,80 @@ * Service container.

/**
* Registers a new constructor parameter handler.
* Registers a new handler.
*/
Container.registerParamHandler = function (paramHandler) {
this.paramHandlers.push(paramHandler);
Container.registerHandler = function (handler) {
this.handlers.push(handler);
};
/**
* Registers a new class property handler.
* Registers a new service.
*/
Container.registerPropertyHandler = function (propertyHandler) {
this.propertyHandlers.push(propertyHandler);
Container.registerService = function (descriptor) {
this.services.push(descriptor);
};
/**
* Registers a new service.
*
* @param name Service name. Optional
* @param type Service class
* @param params Parameters to be sent to constructor on service initialization
* Retrieves the service with given name or type from the service container.
* Optionally, parameters can be passed in case if instance is initialized in the container for the first time.
*/
Container.registerService = function (name, type, params) {
this.registeredServices.push({ name: name, type: type, params: params });
};
Container.get = function (typeOrName, params) {
// normalize parameters
var type, name;
if (typeof typeOrName === "string") {
name = typeOrName;
Container.get = function (identifier) {
// find if service already was registered
var service = this.findService(identifier);
// find if instance of this object already initialized in the container and return it if it is
if (service && service.instance)
return service.instance;
// if named service was requested and its instance was not found plus there is not type to know what to initialize,
// this means service was not pre-registered and we throw an exception
if ((!service || !service.type) && (typeof identifier === "string" || identifier instanceof Token_1.Token))
throw new ServiceNotFoundError_1.ServiceNotFoundError(identifier);
// at this point we either have type in service registered, either identifier is a target type
var type = service && service.type ? service.type : identifier;
// if service was not found then create a new one and register it
if (!service) {
service = { type: type };
this.services.push(service);
}
// setup constructor parameters for a newly initialized service
var params = service.paramTypes ? this.initializeParams(type, service.paramTypes) : [];
// if factory is set then use it to create service instance
if (service.factory) {
// filter out non-service parameters from created service constructor
// non-service parameters can be, lets say Car(name: string, isNew: boolean, engine: Engine)
// where name and isNew are non-service parameters and engine is a service parameter
params = params.filter(function (param) { return param !== undefined; });
if (service.factory instanceof Array) {
// use special [Type, "create"] syntax to allow factory services
// in this case Type instance will be obtained from Container and its method "create" will be called
service.instance = (_a = this.get(service.factory[0]))[service.factory[1]].apply(_a, params);
}
else {
service.instance = service.factory.apply(service, params);
}
}
else {
type = typeOrName;
}
// find if service was already registered
var registeredService = this.findRegisteredService(name, type);
// console.log("registeredService: ", registeredService);
if (registeredService) {
if (!type)
type = registeredService.type;
if (!params)
params = registeredService.params;
}
// find if instance of this object already initialized in the container and return it if it is
var instance = this.findInstance(name, type);
if (instance)
return instance;
// if named service was requested but service was not registered we throw exception
if (!type && name)
throw new Error("Service named " + name + " was not found, probably it was not registered");
// if params are given we need to go throw each of them and initialize them all properly
if (params) {
params = this.initializeParams(type, params);
params.unshift(null);
service.instance = new (type.bind.apply(type, params))();
}
// create a new instance of the requested object
var objectInstance = new (type.bind.apply(type, params))();
this.instances.push({ name: name, type: type, instance: objectInstance });
this.applyPropertyHandlers(type);
return objectInstance;
return service.instance;
var _a;
};
Container.set = function (nameOrType, typeOrValue) {
if (typeof nameOrType === "string") {
this.instances.push({
name: nameOrType,
type: undefined,
instance: typeOrValue
});
/**
* Sets a value for the given type or service name in the container.
*/
Container.set = function (identifier, value) {
var service = this.findService(identifier);
if (service) {
service.instance = value;
}
else {
this.instances.push({
name: undefined,
type: nameOrType,
instance: typeOrValue
});
var service_1 = {
instance: value
};
if (identifier instanceof Token_1.Token || typeof identifier === "string") {
service_1.id = identifier;
}
else {
service_1.type = identifier;
}
this.services.push(service_1);
}
return this;
};

@@ -91,94 +100,93 @@ /**

var _this = this;
values.forEach(function (v) {
if (v.name) {
_this.set(v.name, v.value);
}
else {
_this.set(v.type, v.value);
}
values.forEach(function (v) { return _this.set(v.id, v.value); });
};
/**
* Removes services with a given service identifiers (tokens or types).
*/
Container.remove = function () {
var _this = this;
var ids = [];
for (var _i = 0; _i < arguments.length; _i++) {
ids[_i] = arguments[_i];
}
ids.forEach(function (id) {
var service = _this.findService(id);
if (service)
_this.services.splice(_this.services.indexOf(service), 1);
});
};
/**
* Completely resets the container by removing all previously registered services and handlers from it.
*/
Container.reset = function () {
this.handlers = [];
this.services = [];
};
// -------------------------------------------------------------------------
// Private Static Methods
// -------------------------------------------------------------------------
Container.applyPropertyHandlers = function (target) {
this.propertyHandlers
.filter(function (propertyHandler) { return propertyHandler.target.constructor === target || target.prototype instanceof propertyHandler.target.constructor; })
.forEach(function (propertyHandler) {
Object.defineProperty(propertyHandler.target, propertyHandler.key, {
enumerable: true,
writable: true,
configurable: true,
value: propertyHandler.getValue()
});
/**
* Finds registered service in the with a given service identifier.
*/
Container.findService = function (identifier) {
return this.services.find(function (service) {
if (service.id)
return service.id === identifier;
if (service.type && identifier instanceof Function)
return service.type === identifier || identifier.prototype instanceof service.type;
return false;
});
};
Container.findInstance = function (name, type) {
if (name) {
return this.findInstanceByName(name);
}
else if (type) {
return this.findInstanceByType(type);
}
};
Container.findInstanceByName = function (name) {
return this.instances.reduce(function (found, typeInstance) {
return typeInstance.name === name ? typeInstance.instance : found;
}, undefined);
};
Container.findInstanceByType = function (type) {
return this.instances.filter(function (instance) { return !instance.name; }).reduce(function (found, typeInstance) {
return typeInstance.type === type ? typeInstance.instance : found;
}, undefined);
};
Container.findRegisteredService = function (name, type) {
if (name) {
return this.findRegisteredServiceByName(name);
}
else if (type) {
return this.findRegisteredServiceByType(type);
}
};
Container.findRegisteredServiceByType = function (type) {
return this.registeredServices.filter(function (service) { return !service.name; }).reduce(function (found, service) {
// console.log(service.type, "::", type);
// console.log(type.prototype instanceof service.type);
return service.type === type || type.prototype instanceof service.type ? service : found;
}, undefined);
};
Container.findRegisteredServiceByName = function (name) {
return this.registeredServices.reduce(function (found, service) {
return service.name === name ? service : found;
}, undefined);
};
Container.findParamHandler = function (type, index) {
return this.paramHandlers.reduce(function (found, param) {
return param.type === type && param.index === index ? param : found;
}, undefined);
};
Container.initializeParams = function (type, params) {
/**
* Initializes all parameter types for a given target service class.
*/
Container.initializeParams = function (type, paramTypes) {
var _this = this;
return params.map(function (param, index) {
var paramHandler = Container.findParamHandler(type, index);
return paramTypes.map(function (paramType, index) {
var paramHandler = _this.handlers.find(function (handler) { return handler.object === type && handler.index === index; });
if (paramHandler)
return paramHandler.getValue();
if (param && param.name && !_this.isTypeSimple(param.name))
return Container.get(param);
return paramHandler.value();
if (paramType && paramType.name && !_this.isTypePrimitive(paramType.name))
return Container.get(paramType);
return undefined;
});
};
Container.isTypeSimple = function (param) {
/**
* Checks if given type is primitive (e.g. string, boolean, number, object).
*/
Container.isTypePrimitive = function (param) {
return ["string", "boolean", "number", "object"].indexOf(param.toLowerCase()) !== -1;
};
// -------------------------------------------------------------------------
// Private Static Properties
// -------------------------------------------------------------------------
Container.instances = [];
Container.paramHandlers = [];
Container.propertyHandlers = [];
Container.registeredServices = [];
/**
* Applies all registered handlers on a given target class.
*/
Container.applyPropertyHandlers = function (target) {
this.handlers.forEach(function (handler) {
if (handler.index)
return;
if (handler.object.constructor !== target && !(target.prototype instanceof handler.object.constructor))
return;
Object.defineProperty(handler.object, handler.propertyName, {
enumerable: true,
writable: true,
configurable: true,
value: handler.value()
});
});
};
return Container;
}());
// -------------------------------------------------------------------------
// Private Static Properties
// -------------------------------------------------------------------------
/**
* All registered services.
*/
Container.services = [];
/**
* All registered handlers.
*/
Container.handlers = [];
exports.Container = Container;
//# sourceMappingURL=Container.js.map

@@ -0,2 +1,10 @@

export * from "./decorators/Service";
export * from "./decorators/Inject";
export * from "./decorators/Require";
export { Container } from "./Container";
export * from "./decorators";
export { Token } from "./Token";
export { Handler } from "./types/Handler";
export { ServiceOptions } from "./types/ServiceOptions";
export { ServiceIdentifier } from "./types/ServiceIdentifier";
export { ServiceMetadata } from "./types/ServiceMetadata";
export { ObjectType } from "./types/ObjectType";

@@ -5,6 +5,11 @@ "use strict";

}
Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./decorators/Service"));
__export(require("./decorators/Inject"));
__export(require("./decorators/Require"));
var Container_1 = require("./Container");
exports.Container = Container_1.Container;
__export(require("./decorators"));
var Token_1 = require("./Token");
exports.Token = Token_1.Token;
//# sourceMappingURL=index.js.map
{
"name": "typedi",
"version": "0.4.3",
"version": "0.5.0",
"description": "Dependency injection for TypeScript",

@@ -21,28 +21,32 @@ "license": "MIT",

"di",
"container",
"di-container",
"typescript",
"typescript-di",
"dependency-injection",
"typescript-require"
"dependency-injection"
],
"dependencies": {},
"devDependencies": {
"@types/chai": "^3.5.1",
"@types/mocha": "^2.2.41",
"@types/node": "^7.0.13",
"@types/sinon": "^2.1.2",
"chai": "^3.4.1",
"del": "^2.2.1",
"es6-shim": "^0.35.1",
"gulp": "^3.9.1",
"gulp-mocha": "^2.2.0",
"gulp-mocha": "^3.0.1",
"gulp-replace": "^0.5.4",
"gulp-shell": "^0.5.1",
"gulp-sourcemaps": "^1.6.0",
"gulp-tslint": "^6.0.1",
"gulp-typescript": "^2.13.6",
"gulpclass": "^0.1.1",
"mocha": "^2.5.3",
"reflect-metadata": "^0.1.3",
"sinon": "^1.17.4",
"sinon-chai": "^2.8.0",
"tslint": "^3.13.0",
"tslint-stylish": "^2.1.0-beta",
"typescript": "^1.8.10",
"typings": "^1.3.1"
"gulp-shell": "^0.6.3",
"gulp-sourcemaps": "^2.6.0",
"gulp-tslint": "^8.0.0",
"gulp-typescript": "^3.1.6",
"gulpclass": "^0.1.2",
"mocha": "^3.2.0",
"reflect-metadata": "^0.1.10",
"sinon": "^2.1.0",
"sinon-chai": "^2.9.0",
"ts-node": "^3.0.2",
"tslint": "^5.1.0",
"tslint-stylish": "^2.1.0",
"typescript": "^2.2.2"
},

@@ -49,0 +53,0 @@ "scripts": {

# TypeDI
Dependency injection tool for Typescript.
Simple yet powerful dependency injection tool for Typescript.

@@ -12,14 +12,24 @@ ## Installation

2. Use [typings](https://github.com/typings/typings) to install all required definition dependencies.
2. You also need to install [reflect-metadata](https://www.npmjs.com/package/reflect-metadata) package.
`typings install`
`npm install reflect-metadata --save`
and import it somewhere in the global place of your app (for example in `app.ts`):
`import "reflect-metadata";`
3. ES6 features are used, so you may want to install [es6-shim](https://github.com/paulmillr/es6-shim) too. You also
need to install [reflect-metadata](https://www.npmjs.com/package/reflect-metadata) package.
3. You may need to install node typings:
`npm install es6-shim --save`
`npm install reflect-metadata --save`
`npm install @types/node --save`
if you are building nodejs app, you may want to `require("es6-shim");` and `require("reflect-metadata")` in your app.
4. Also make sure you are using TypeScript compiler version > **2.1**
and you have enabled following settings in `tsconfig.json`:
```json
"lib": ["es6"],
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
```
## Usage

@@ -46,4 +56,5 @@

```javascript
import {Container, Inject} from "typedi";
import {Container, Inject, Service} from "typedi";
@Service()
class BeanFactory {

@@ -54,2 +65,3 @@ create() {

@Service()
class SugarFactory {

@@ -60,2 +72,3 @@ create() {

@Service()
class WaterFactory {

@@ -66,2 +79,3 @@ create() {

@Service()
class CoffeeMaker {

@@ -95,2 +109,3 @@

@Service()
class BeanFactory {

@@ -101,2 +116,3 @@ create() {

@Service()
class SugarFactory {

@@ -107,2 +123,3 @@ create() {

@Service()
class WaterFactory {

@@ -139,6 +156,6 @@ create() {

> note: Your classes may not to have `@Service` decorator to use it with Container, however its recommended to add
`@Service` decorator to all classes you are using with container, especially if you class injects other
services
`@Service` decorator to all classes you are using with container, because without `@Service` decorator applied
constructor injection may not work properly in your classes.
### Extra feature: Injecting third-party dependencies *(experimental)*
### Injecting third-party dependencies *(experimental)*

@@ -153,10 +170,10 @@ Also you can inject a modules that you want to `require`:

private gulp: any; // you can use type if you have definition for this package
private logger: any; // you can use type if you have definition for this package
constructor(@Require("gulp") gulp: any) {
this.gulp = gulp; // the same if you do this.gulp = require("gulp")
constructor(@Require("logger") logger: any) {
this.logger = logger; // the same if you do this.logger = require("logger")
}
make() {
console.log(this.gulp); // here you get console.logged gulp package =)
console.log(this.logger); // here you get console.logged logger package =)
}

@@ -225,2 +242,100 @@ }

### Services with token name
You can use a services with a `Token` instead of name or target class.
In this case you can use type safe interface-based services.
```javascript
import {Container, Service, Inject, Token} from "typedi";
export interface Factory {
create(): void;
}
export const FactoryService = new Token<Factory>();
@Service(FactoryService)
export class BeanFactory implements Factory {
create() {
}
}
@Service()
export class CoffeeMaker {
private factory: Factory;
constructor(@Inject(FactoryService) factory: Factory) {
this.factory = factory;
}
make() {
this.factory.create();
}
}
let coffeeMaker = Container.get(CoffeeMaker);
coffeeMaker.make();
let factory = Container.get(FactoryService);
factory.create();
```
### Using factory function to create service
You can create your services with the container using factory functions.
This way, service instance will be created by calling your factory function instead of
instantiating a class directly.
```javascript
import {Container, Service} from "typedi";
function createCar() {
return new Car("V8");
}
@Service({ factory: createCar })
class Car {
constructor (public engineType: string) {
}
}
// Getting service from the container.
// Service will be created by calling the specified factory function.
const car = Container.get(Car);
console.log(car.engineType); // > "V8"
```
### Using factory class to create service
You can also create your services using factory classes.
This way, service instance will be created by calling given factory service's method factory instead of
instantiating a class directly.
```javascript
import {Container, Service} from "typedi";
@Service()
class CarFactory {
constructor(public logger: LoggerService) {
}
create() {
return new Car("BMW", this.logger);
}
}
@Service({ factory: [CarFactory, "create"] })
class Car {
constructor(public model: string, public logger: LoggerInterface) {
}
}
```
### Providing values to the container

@@ -234,8 +349,8 @@

// or alternatively:
// or
Container.provide([
{ name: "bean.factory", type: BeanFactory, value: new FakeBeanFactory() },
{ name: "sugar.factory", type: SugarFactory, value: new FakeSugarFactory() },
{ name: "water.factory", type: WaterFactory, value: new FakeWaterFactory() }
{ id: "bean.factory", value: new FakeBeanFactory() },
{ id: "sugar.factory", value: new FakeSugarFactory() },
{ id: "water.factory", value: new FakeWaterFactory() }
]);

@@ -265,3 +380,3 @@ ```

This code will not work, because Engine has a reference to Car, and Car has a reference to Engine.
One of them will be undefined and it will cause an errors. To fix them you need to specify a type in a function like this:
One of them will be undefined and it cause errors. To fix them you need to specify a type in a function this way:

@@ -309,2 +424,54 @@ ```javascript

### Custom decorators
You can create your own decorators which will inject your given values for your service dependencies.
For example:
```javascript
// Logger.ts
export function Logger() {
return function(object: Object, propertyName: string, index?: number) {
const logger = new ConsoleLogger();
Container.registerHandler({ object, propertyName, index, value: () => logger });
};
}
// LoggerInterface.ts
export interface LoggerInterface {
log(message: string): void;
}
// ConsoleLogger.ts
import {LoggerInterface} from "./LoggerInterface";
export class ConsoleLogger implements LoggerInterface {
log(message: string) {
console.log(message);
}
}
// UserRepository.ts
@Service()
export class UserRepository {
constructor(@Logger() private logger: LoggerInterface) {
}
save(user: User) {
this.logger.log(`user ${user.firstName} ${user.secondName} has been saved.`);
}
}
```
### Remove registered services or reset container state
If you need to remove registered service from container simply use `Container.remove(...)` method.
Also you can completely reset the container by calling `Container.reset()` method.
This will effectively remove all registered services from the container.
## Samples

@@ -311,0 +478,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc