1
1
# TypeDI
2
2
3
- Dependency injection tool for Typescript.
3
+ Simple yet powerful dependency injection tool for Typescript.
4
4
5
5
## Installation
6
6
@@ -9,17 +9,27 @@ Dependency injection tool for Typescript.
9
9
10
10
` npm install typedi --save `
11
11
12
- 2 . Use [ typings ] ( https://github. com/typings/typings ) to install all required definition dependencies .
12
+ 2 . You also need to install [ reflect-metadata ] ( https://www.npmjs. com/package/reflect-metadata ) package .
13
13
14
- ` typings install `
14
+ ` npm install reflect-metadata --save `
15
+
16
+ and import it somewhere in the global place of your app (for example in ` app.ts ` ):
17
+
18
+ ` import "reflect-metadata"; `
15
19
16
- 3 . ES6 features are used, so you may want to install [ es6-shim] ( https://github.com/paulmillr/es6-shim ) too. You also
17
- need to install [ reflect-metadata] ( https://www.npmjs.com/package/reflect-metadata ) package.
20
+ 3 . You may need to install node typings:
18
21
19
- `npm install es6-shim --save`
20
- `npm install reflect-metadata --save`
22
+ ` npm install @types/node --save `
23
+
24
+
25
+ 4 . Also make sure you are using TypeScript compiler version > ** 2.1**
26
+ and you have enabled following settings in ` tsconfig.json ` :
21
27
22
- if you are building nodejs app, you may want to `require("es6-shim");` and `require("reflect-metadata")` in your app.
28
+ ``` json
29
+ "lib" : [" es6" ],
30
+ "emitDecoratorMetadata" : true ,
31
+ "experimentalDecorators" : true ,
32
+ ```
23
33
24
34
## Usage
25
35
@@ -42,23 +52,27 @@ someClass.someMethod();
42
52
If you want to inject other classes into your service you can do:
43
53
44
54
``` typescript
45
- import {Container , Inject } from " typedi" ;
55
+ import {Container , Inject , Service } from " typedi" ;
46
56
57
+ @Service ()
47
58
class BeanFactory {
48
59
create() {
49
60
}
50
61
}
51
62
63
+ @Service ()
52
64
class SugarFactory {
53
65
create() {
54
66
}
55
67
}
56
68
69
+ @Service ()
57
70
class WaterFactory {
58
71
create() {
59
72
}
60
73
}
61
74
75
+ @Service ()
62
76
class CoffeeMaker {
63
77
64
78
@Inject ()
@@ -87,16 +101,19 @@ If you want to use constructor injection:
87
101
``` typescript
88
102
import {Container , Service } from " typedi" ;
89
103
104
+ @Service ()
90
105
class BeanFactory {
91
106
create() {
92
107
}
93
108
}
94
109
110
+ @Service ()
95
111
class SugarFactory {
96
112
create() {
97
113
}
98
114
}
99
115
116
+ @Service ()
100
117
class WaterFactory {
101
118
create() {
102
119
}
@@ -128,10 +145,10 @@ coffeeMaker.make();
128
145
```
129
146
130
147
> note: Your classes may not to have ` @Service ` decorator to use it with Container, however its recommended to add
131
- ` @Service ` decorator to all classes you are using with container, especially if you class injects other
132
- services
148
+ ` @Service ` decorator to all classes you are using with container, because without ` @Service ` decorator applied
149
+ constructor injection may not work properly in your classes.
133
150
134
- ### Extra feature: Injecting third-party dependencies * (experimental)*
151
+ ### Injecting third-party dependencies * (experimental)*
135
152
136
153
Also you can inject a modules that you want to ` require ` :
137
154
@@ -141,14 +158,14 @@ import {Container, Service, Require} from "typedi";
141
158
@Service ()
142
159
class CoffeeMaker {
143
160
144
- private gulp : any ; // you can use type if you have definition for this package
161
+ private logger : any ; // you can use type if you have definition for this package
145
162
146
- constructor (@Require (" gulp " ) gulp : any ) {
147
- this .gulp = gulp ; // the same if you do this.gulp = require("gulp ")
163
+ constructor (@Require (" logger " ) logger : any ) {
164
+ this .logger = logger ; // the same if you do this.logger = require("logger ")
148
165
}
149
166
150
167
make() {
151
- console .log (this .gulp ); // here you get console.logged gulp package =)
168
+ console .log (this .logger ); // here you get console.logged logger package =)
152
169
}
153
170
}
154
171
@@ -212,24 +229,63 @@ let coffeeMaker = Container.get<CoffeeMaker>("coffee.maker");
212
229
coffeeMaker .make ();
213
230
```
214
231
232
+ ### Services with token name
233
+
234
+ You can use a services with a ` Token ` instead of name or target class.
235
+ In this case you can use type safe interface-based services.
236
+
237
+ ``` typescript
238
+ import {Container , Service , Inject , Token } from " typedi" ;
239
+
240
+ export interface Factory {
241
+ create(): void ;
242
+ }
243
+
244
+ export const FactoryService = new Token <Factory >();
245
+
246
+ @Service (FactoryService )
247
+ export class BeanFactory implements Factory {
248
+ create() {
249
+ }
250
+ }
251
+
252
+ @Service ()
253
+ export class CoffeeMaker {
254
+
255
+ private factory: Factory ;
256
+
257
+ constructor (@Inject (FactoryService ) factory : Factory ) {
258
+ this .factory = factory ;
259
+ }
260
+
261
+ make() {
262
+ this .factory .create ();
263
+ }
264
+
265
+ }
266
+
267
+ let coffeeMaker = Container .get (CoffeeMaker );
268
+ coffeeMaker .make ();
269
+
270
+ let factory = Container .get (FactoryService );
271
+ factory .create ();
272
+ ```
273
+
215
274
### Using factory function to create service
216
275
217
- You can register your services with the container using factory functions.
276
+ You can create your services with the container using factory functions.
218
277
219
278
This way, service instance will be created by calling your factory function instead of
220
279
instantiating a class directly.
221
280
222
281
``` typescript
223
282
import {Container , Service } from " typedi" ;
224
283
225
-
226
- class CarFactory {
227
- public static createCar(): Car {
228
- return new Car (" V8" );
229
- }
284
+ function createCar() {
285
+ return new Car (" V8" );
230
286
}
231
287
232
- @Service ({ factory: CarFactory . createCar })
288
+ @Service ({ factory: createCar })
233
289
class Car {
234
290
constructor (public engineType : string ) {
235
291
}
@@ -242,6 +298,35 @@ const car = Container.get(Car);
242
298
console .log (car .engineType ); // > "V8"
243
299
```
244
300
301
+ ### Using factory class to create service
302
+
303
+ You can also create your services using factory classes.
304
+
305
+ This way, service instance will be created by calling given factory service's method factory instead of
306
+ instantiating a class directly.
307
+
308
+ ``` typescript
309
+ import {Container , Service } from " typedi" ;
310
+
311
+ @Service ()
312
+ class CarFactory {
313
+
314
+ constructor (public logger : LoggerService ) {
315
+ }
316
+
317
+ create() {
318
+ return new Car (" BMW" , this .logger );
319
+ }
320
+
321
+ }
322
+
323
+ @Service ({ factory: [CarFactory , " create" ] })
324
+ class Car {
325
+ constructor (public model : string , public logger : LoggerInterface ) {
326
+ }
327
+ }
328
+ ```
329
+
245
330
### Providing values to the container
246
331
247
332
If you are writing unit tests for you class, you may want to provide fakes to your classes. You can use ` set ` or
@@ -250,12 +335,12 @@ If you are writing unit tests for you class, you may want to provide fakes to yo
250
335
``` typescript
251
336
Container .set (CoffeeMaker , new FakeCoffeeMaker ());
252
337
253
- // or alternatively:
338
+ // or
254
339
255
340
Container .provide ([
256
- { name : " bean.factory" , type: BeanFactory , value: new FakeBeanFactory () },
257
- { name : " sugar.factory" , type: SugarFactory , value: new FakeSugarFactory () },
258
- { name : " water.factory" , type: WaterFactory , value: new FakeWaterFactory () }
341
+ { id : " bean.factory" , value: new FakeBeanFactory () },
342
+ { id : " sugar.factory" , value: new FakeSugarFactory () },
343
+ { id : " water.factory" , value: new FakeWaterFactory () }
259
344
]);
260
345
```
261
346
@@ -280,7 +365,7 @@ export class Engine {
280
365
```
281
366
282
367
This code will not work, because Engine has a reference to Car, and Car has a reference to Engine.
283
- 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:
368
+ One of them will be undefined and it cause errors. To fix them you need to specify a type in a function this way :
284
369
285
370
``` typescript
286
371
// Car.ts
@@ -323,10 +408,57 @@ export class Bus extends Car {
323
408
}
324
409
```
325
410
326
- ### Container reset
411
+ ### Custom decorators
412
+
413
+ You can create your own decorators which will inject your given values for your service dependencies.
414
+ For example:
415
+
416
+ ``` typescript
417
+ // Logger.ts
418
+ export function Logger() {
419
+ return function (object : Object , propertyName : string , index ? : number ) {
420
+ const logger = new ConsoleLogger ();
421
+ Container .registerHandler ({ object , propertyName , index , value : () => logger });
422
+ };
423
+ }
424
+
425
+ // LoggerInterface.ts
426
+ export interface LoggerInterface {
427
+
428
+ log(message : string ): void ;
429
+
430
+ }
431
+
432
+ // ConsoleLogger.ts
433
+ import {LoggerInterface } from " ./LoggerInterface" ;
434
+
435
+ export class ConsoleLogger implements LoggerInterface {
436
+
437
+ log(message : string ) {
438
+ console .log (message );
439
+ }
440
+
441
+ }
442
+
443
+ // UserRepository.ts
444
+ @Service ()
445
+ export class UserRepository {
446
+
447
+ constructor (@Logger () private logger : LoggerInterface ) {
448
+ }
449
+
450
+ save(user : User ) {
451
+ this .logger .log (` user ${user .firstName } ${user .secondName } has been saved. ` );
452
+ }
453
+
454
+ }
455
+ ```
456
+
457
+ ### Remove registered services or reset container state
327
458
328
- You can reset the container by calling ` Container.reset() ` method.
329
- This will effectively remove references to all registered artifacts from it, making it pristine (empty).
459
+ If you need to remove registered service from container simply use ` Container.remove(...) ` method.
460
+ Also you can completely reset the container by calling ` Container.reset() ` method.
461
+ This will effectively remove all registered services from the container.
330
462
331
463
## Samples
332
464
0 commit comments