Skip to content

Commit 685bf50

Browse files
committed
merge master
2 parents c7011a9 + 43ebb5d commit 685bf50

34 files changed

+4350
-229
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Changelog
2+
3+
## 0.6.0
4+
5+
* added multiple containers support
6+
* added grouped (tagged) containers support
7+
* removed `provide` method, use `set` method instead
8+
* deprecated `Require` decorator. Use es6 imports instead or named services
9+
* inherited classes don't need to be decorated with `@Service` decorator
10+
* other small api changes
11+
* now `Handler`'s `value` accepts a container which requests the value

README.md

Lines changed: 177 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# TypeDI
22

3-
[![Build Status](https://travis-ci.org/pleerock/typedi.svg?branch=master)](https://travis-ci.org/pleerock/typedi)
3+
[![Build Status](https://travis-ci.org/typestack/typedi.svg?branch=master)](https://travis-ci.org/typestack/typedi)
44
[![npm version](https://badge.fury.io/js/typedi.svg)](https://badge.fury.io/js/typedi)
5-
[![Dependency Status](https://david-dm.org/pleerock/typedi.svg)](https://david-dm.org/pleerock/typedi)
6-
[![Join the chat at https://gitter.im/pleerock/typedi](https://badges.gitter.im/pleerock/typedi.svg)](https://gitter.im/pleerock/typedi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
5+
[![Dependency Status](https://david-dm.org/typestack/typedi.svg)](https://david-dm.org/typestack/typedi)
6+
[![Join the chat at https://gitter.im/typestack/typedi](https://badges.gitter.im/typestack/typedi.svg)](https://gitter.im/typestack/typedi?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
77

8-
Simple yet powerful dependency injection tool for TypeScript.
8+
TypeDI is a [dependency injection](https://en.wikipedia.org/wiki/Dependency_injection) tool for TypeScript.
9+
Using TypeDI you can build well-structured and easily tested applications.
910

1011
## Installation
1112

@@ -37,7 +38,7 @@ and you have enabled following settings in `tsconfig.json`:
3738

3839
## Usage
3940

40-
If you simply want to use a container:
41+
The most simple usage example is:
4142

4243
```typescript
4344
import {Container} from "typedi";
@@ -53,7 +54,26 @@ let someClass = Container.get(SomeClass);
5354
someClass.someMethod();
5455
```
5556

56-
If you want to inject other classes into your service you can do:
57+
Then you can call `Container.get(SomeClass)` from anywhere in your application
58+
and you'll always have the same instance of `SomeClass`.
59+
60+
If you want to use more advanced functionality you need to mark your class with `@Service` decorator:
61+
62+
```typescript
63+
import {Service} from "typedi";
64+
65+
@Service()
66+
class SomeClass {
67+
68+
someMethod() {
69+
}
70+
71+
}
72+
```
73+
74+
Its recommended to always use `@Service` decorator on your service classes.
75+
76+
You can services into your class using `@Inject` decorator:
5777

5878
```typescript
5979
import {Container, Inject, Service} from "typedi";
@@ -100,7 +120,7 @@ let coffeeMaker = Container.get(CoffeeMaker);
100120
coffeeMaker.make();
101121
```
102122

103-
If you want to use constructor injection:
123+
You can also use a constructor injection:
104124

105125
```typescript
106126
import {Container, Service} from "typedi";
@@ -142,38 +162,25 @@ let coffeeMaker = Container.get(CoffeeMaker);
142162
coffeeMaker.make();
143163
```
144164

145-
> note: Your classes may not to have `@Service` decorator to use it with Container, however its recommended to add
146-
`@Service` decorator to all classes you are using with container, because without `@Service` decorator applied
147-
constructor injection may not work properly in your classes.
165+
## Advanced usage
148166

149-
### Injecting third-party dependencies *(experimental)*
150-
151-
Also you can inject a modules that you want to `require`:
152-
153-
```typescript
154-
import {Container, Service, Require} from "typedi";
155-
156-
@Service()
157-
class CoffeeMaker {
158-
159-
private logger: any; // you can use type if you have definition for this package
160-
161-
constructor(@Require("logger") logger: any) {
162-
this.logger = logger; // the same if you do this.logger = require("logger")
163-
}
164-
165-
make() {
166-
console.log(this.logger); // here you get console.logged logger package =)
167-
}
168-
}
167+
* [Named services](#named-services)
168+
* [Services with token name](#services-with-token-name)
169+
* [Using factory function to create service](#using-factory-function-to-create-service)
170+
* [Using factory class to create service](#using-factory-class-to-create-service)
171+
* [Providing values to the container](#providing-values-to-the-container)
172+
* [Problem with circular references](#problem-with-circular-references)
173+
* [Inherited injections](#inherited-injections)
174+
* [Custom decorators](#custom-decorators)
175+
* [Using service groups](#using-service-groups)
176+
* [Using multiple containers and scoped containers](#using-multiple-containers-and-scoped-containers)
177+
* [Remove registered services or reset container state](#remove-registered-services-or-reset-container-state)
169178

170-
let coffeeMaker = Container.get(CoffeeMaker);
171-
coffeeMaker.make();
172-
```
173179

174180
### Named services
175181

176-
You can use a named services. In this case you can use interface-based services.
182+
You can use a named services.
183+
This feature is especially useful when you want to create a service for the interface.
177184

178185
```typescript
179186
import {Container, Service, Inject} from "typedi";
@@ -227,6 +234,24 @@ let coffeeMaker = Container.get<CoffeeMaker>("coffee.maker");
227234
coffeeMaker.make();
228235
```
229236

237+
This feature is also useful if you want to store (and inject later on) some settings or configuration options.
238+
For example:
239+
240+
```typescript
241+
import {Container, Service, Inject} from "typedi";
242+
243+
// somewhere in your global app parameters
244+
Container.set("authorization-token", "RVT9rVjSVN");
245+
246+
@Service()
247+
class UserRepository {
248+
249+
@Inject("authorization-token")
250+
authorizationToken: string;
251+
252+
}
253+
```
254+
230255
### Services with token name
231256

232257
You can use a services with a `Token` instead of name or target class.
@@ -265,7 +290,7 @@ export class CoffeeMaker {
265290
let coffeeMaker = Container.get(CoffeeMaker);
266291
coffeeMaker.make();
267292

268-
let factory = Container.get(FactoryService);
293+
let factory = Container.get(FactoryService); // factory is instance of Factory
269294
factory.create();
270295
```
271296

@@ -335,7 +360,7 @@ Container.set(CoffeeMaker, new FakeCoffeeMaker());
335360

336361
// or
337362

338-
Container.provide([
363+
Container.set([
339364
{ id: "bean.factory", value: new FakeBeanFactory() },
340365
{ id: "sugar.factory", value: new FakeSugarFactory() },
341366
{ id: "water.factory", value: new FakeWaterFactory() }
@@ -381,7 +406,7 @@ export class Engine {
381406
}
382407
```
383408

384-
And that's all. Same for injects for constructor injection.
409+
And that's all. Same for constructor injections.
385410

386411
### Inherited injections
387412

@@ -393,7 +418,7 @@ For example:
393418
@Service()
394419
export abstract class Car {
395420

396-
@Inject(type => Engine)
421+
@Inject()
397422
engine: Engine;
398423

399424
}
@@ -416,7 +441,7 @@ For example:
416441
export function Logger() {
417442
return function(object: Object, propertyName: string, index?: number) {
418443
const logger = new ConsoleLogger();
419-
Container.registerHandler({ object, propertyName, index, value: () => logger });
444+
Container.registerHandler({ object, propertyName, index, value: containerInstance => logger });
420445
};
421446
}
422447

@@ -452,6 +477,116 @@ export class UserRepository {
452477
}
453478
```
454479

480+
### Using service groups
481+
482+
You can group multiple services into single group tagged with service id or token.
483+
For example:
484+
485+
```typescript
486+
// Factory.ts
487+
export interface Factory {
488+
create(): any;
489+
}
490+
491+
// FactoryToken.ts
492+
export const FactoryToken = new Token<Factory>("factories");
493+
494+
// BeanFactory.ts
495+
@Service({ id: FactoryToken, multiple: true })
496+
export class BeanFactory implements Factory {
497+
498+
create() {
499+
console.log("bean created");
500+
}
501+
502+
}
503+
504+
// SugarFactory.ts
505+
@Service({ id: FactoryToken, multiple: true })
506+
export class SugarFactory implements Factory {
507+
508+
create() {
509+
console.log("sugar created");
510+
}
511+
512+
}
513+
514+
// WaterFactory.ts
515+
@Service({ id: FactoryToken, multiple: true })
516+
export class WaterFactory implements Factory {
517+
518+
create() {
519+
console.log("water created");
520+
}
521+
522+
}
523+
524+
// app.ts
525+
// now you can get all factories in a single array
526+
const factories = Container.getMany(FactoryToken); // factories is Factory[]
527+
factories.forEach(factory => factory.create());
528+
```
529+
530+
### Using multiple containers and scoped containers
531+
532+
By default all services are stored in the global service container,
533+
and this global service container holds all unique instances of each service you have.
534+
535+
If you want your services to behave and store data inside differently,
536+
based on some user context (http request for example) -
537+
you can use different containers for different contexts.
538+
For example:
539+
540+
```typescript
541+
// QuestionController.ts
542+
@Service()
543+
export class QuestionController {
544+
545+
constructor(protected questionRepository: QuestionRepository) {
546+
}
547+
548+
save() {
549+
this.questionRepository.save();
550+
}
551+
}
552+
553+
// QuestionRepository.ts
554+
@Service()
555+
export class QuestionRepository {
556+
557+
save() {
558+
}
559+
560+
}
561+
562+
// app.ts
563+
const request1 = { param: "question1" };
564+
const controller1 = Container.of(request1).get(QuestionController);
565+
controller1.save("Timber");
566+
Container.reset(request1);
567+
568+
const request2 = { param: "question2" };
569+
const controller2 = Container.of(request2).get(QuestionController);
570+
controller2.save("");
571+
Container.reset(request2);
572+
```
573+
574+
In this example `controller1` and `controller2` are completely different instances,
575+
and `QuestionRepository` used in those controllers are different instances as well.
576+
577+
`Container.reset` removes container with the given context identifier.
578+
If you want your services to be completely global and not be container-specific,
579+
you can mark them as global:
580+
581+
```typescript
582+
@Service({ global: true })
583+
export class QuestionUtils {
584+
585+
}
586+
```
587+
588+
And this global service will be the same instance across all containers.
589+
455590
### Remove registered services or reset container state
456591

457592
If you need to remove registered service from container simply use `Container.remove(...)` method.
@@ -466,9 +601,9 @@ In order to use typedi with routing-controllers and/or typeorm, it's **necessary
466601
Otherwise you may face [this kind of issue](https://github.com/pleerock/typedi/issues/4).
467602

468603
```Typescript
469-
import { useContainer as routingUseContainer } from 'routing-controllers';
470-
import { useContainer as ormUseContainer } from 'typeorm';
471-
import { Container } from "typedi";
604+
import {useContainer as routingUseContainer} from "routing-controllers";
605+
import {useContainer as ormUseContainer} from "typeorm";
606+
import {Container} from "typedi";
472607

473608
routingUseContainer(Container);
474609
ormUseContainer(Container);

0 commit comments

Comments
 (0)