Skip to content

Commit 8018b49

Browse files
author
Umed Khudoiberdiev
committed
multiple fixes and prepare for 0.6.0 release
1 parent bc64667 commit 8018b49

File tree

9 files changed

+182
-23
lines changed

9 files changed

+182
-23
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## 0.6.0
44

5+
* added multiple containers support
6+
* added grouped (tagged) containers support
57
* removed `provide` method, use `set` method instead
68
* deprecated `Require` decorator. Use es6 imports instead or named services
7-
* other small api changes
9+
* inherited classes don't need to be decorated with `@Service` decorator
10+
* other small api changes

README.md

Lines changed: 174 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
[![Dependency Status](https://david-dm.org/pleerock/typedi.svg)](https://david-dm.org/pleerock/typedi)
66
[![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)
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,13 +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
166+
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)
178+
148179

149180
### Named services
150181

151-
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.
152184

153185
```typescript
154186
import {Container, Service, Inject} from "typedi";
@@ -202,6 +234,24 @@ let coffeeMaker = Container.get<CoffeeMaker>("coffee.maker");
202234
coffeeMaker.make();
203235
```
204236

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+
205255
### Services with token name
206256

207257
You can use a services with a `Token` instead of name or target class.
@@ -240,7 +290,7 @@ export class CoffeeMaker {
240290
let coffeeMaker = Container.get(CoffeeMaker);
241291
coffeeMaker.make();
242292

243-
let factory = Container.get(FactoryService);
293+
let factory = Container.get(FactoryService); // factory is instance of Factory
244294
factory.create();
245295
```
246296

@@ -356,7 +406,7 @@ export class Engine {
356406
}
357407
```
358408

359-
And that's all. Same for injects for constructor injection.
409+
And that's all. Same for constructor injections.
360410

361411
### Inherited injections
362412

@@ -368,7 +418,7 @@ For example:
368418
@Service()
369419
export abstract class Car {
370420

371-
@Inject(type => Engine)
421+
@Inject()
372422
engine: Engine;
373423

374424
}
@@ -427,6 +477,116 @@ export class UserRepository {
427477
}
428478
```
429479

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+
430590
### Remove registered services or reset container state
431591

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

443603
```Typescript
444-
import { useContainer as routingUseContainer } from 'routing-controllers';
445-
import { useContainer as ormUseContainer } from 'typeorm';
446-
import { Container } from "typedi";
604+
import {useContainer as routingUseContainer} from "routing-controllers";
605+
import {useContainer as ormUseContainer} from "typeorm";
606+
import {Container} from "typedi";
447607

448608
routingUseContainer(Container);
449609
ormUseContainer(Container);

sample/sample7-inherited-properties/Car.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
import {Service} from "../../src/decorators/Service";
21
import {Inject} from "../../src/decorators/Inject";
32
import {Driver} from "./Driver";
43
import {Engine} from "./Engine";
54

6-
@Service()
75
export abstract class Car {
86

9-
@Inject(type => Driver)
7+
@Inject()
108
driver: Driver;
119

12-
@Inject(type => Engine)
10+
@Inject()
1311
engine: Engine;
1412

1513
year = 2016;

sample/sample7-inherited-properties/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {PorsheCar} from "./PorsheCar";
55

66
// drive bmw
77
let bmwCar = Container.get(BmwCar);
8+
console.log(bmwCar);
89
bmwCar.drive();
910

1011
// drive porshe

sample/sample8-tokenized-services/app.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
import "reflect-metadata";
22
import {Container} from "../../src/index";
3-
import "./BodyFactory";
4-
import "./WheelFactory";
5-
import "./EngineFactory";
6-
import "./CarFactory";
73
import {ReaderService, StoreService} from "./Tokens";
84
import {FtpStore} from "./FtpStore";
95
import {FtpReader} from "./FtpReader";

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from "./decorators/Service";
22
export * from "./decorators/Inject";
33
export * from "./decorators/Require";
44
export {Container} from "./Container";
5+
export {ContainerInstance} from "./ContainerInstance";
56
export {Token} from "./Token";
67
export {Handler} from "./types/Handler";
78
export {ServiceOptions} from "./types/ServiceOptions";

0 commit comments

Comments
 (0)