@@ -4,7 +4,7 @@ We try to provide developers with useful error feedback like:
4
4
5
5
> Error: Missing required @injectable annotation in: SamuraiMaster
6
6
7
- This works fine in most cases but it causes some problem when using inheritance.
7
+ This works fine in most cases but it causes some problem when using inheritance.
8
8
9
9
For example, the following code snippet throws a misleading error:
10
10
@@ -20,9 +20,9 @@ class Warrior {
20
20
}
21
21
22
22
@injectable ()
23
- class SamuraiMaster extends Warrior {
23
+ class SamuraiMaster extends Warrior {
24
24
public constructor () { // args count = 0
25
- super (" master" );
25
+ super (" master" );
26
26
}
27
27
}
28
28
```
@@ -39,18 +39,17 @@ If you don't follow this rule an exception will be thrown:
39
39
40
40
The users have a few ways to overcome this limitation available:
41
41
42
- ### WORKAROUND A) Use the @unmanaged decorator
42
+ ### WORKAROUND A) Use the @unmanaged decorator
43
+
43
44
The ` @unmanaged() ` decorator allow users to flag that an argument will
44
- be manually injected into a base class. We use the word "unmanaged"
45
- because InversifyJS does not have control under user provided values
45
+ be manually injected into a base class. We use the word "unmanaged"
46
+ because InversifyJS does not have control under user provided values
46
47
and it doesn't manage their injection.
47
48
48
49
The following code snippet showcases how to apply this decorator:
49
50
50
51
``` ts
51
- import {
52
- Container , injectable , unmanaged
53
- } from " ../src/inversify" ;
52
+ import { Container , injectable , unmanaged } from " ../src/inversify" ;
54
53
55
54
const BaseId = " Base" ;
56
55
@@ -78,7 +77,7 @@ derived.prop; // "unmanaged-injected-value"
78
77
79
78
### WORKAROUND B) Property setter
80
79
81
- You can use the ` public ` , ` protected ` or ` private ` access modifier and a
80
+ You can use the ` public ` , ` protected ` or ` private ` access modifier and a
82
81
property setter to avoid injecting into the base class:
83
82
84
83
``` ts
@@ -93,8 +92,8 @@ class Warrior {
93
92
@injectable ()
94
93
class SamuraiMaster extends Warrior {
95
94
public constructor () { // args count = 0
96
- super ();
97
- this .rank = " master" ;
95
+ super ();
96
+ this .rank = " master" ;
98
97
}
99
98
}
100
99
```
@@ -113,26 +112,26 @@ class Warrior {
113
112
let TYPES = { Rank: " Rank" };
114
113
115
114
@injectable ()
116
- class SamuraiMaster extends Warrior {
117
-
115
+ class SamuraiMaster extends Warrior {
118
116
@injectNamed (TYPES .Rank , " master" )
119
117
@named (" master" )
120
118
protected rank: string ;
121
-
119
+
122
120
public constructor () { // args count = 0
123
- super ();
121
+ super ();
124
122
}
125
123
}
126
124
127
- container .bind <string >(TYPES .Rank )
128
- .toConstantValue (" master" )
129
- .whenTargetNamed (" master" );
125
+ container
126
+ .bind <string >(TYPES .Rank )
127
+ .toConstantValue (" master" )
128
+ .whenTargetNamed (" master" );
130
129
```
131
130
132
131
### WORKAROUND D) Inject into the derived class
133
132
134
- If we don't want to avoid injecting into the base class we can
135
- inject into the derived class and then into the base class using
133
+ If we don't want to avoid injecting into the base class we can
134
+ inject into the derived class and then into the base class using
136
135
its constructor (super).
137
136
138
137
``` ts
@@ -147,17 +146,18 @@ class Warrior {
147
146
let TYPES = { Rank: " Rank" };
148
147
149
148
@injectable ()
150
- class SamuraiMaster extends Warrior {
149
+ class SamuraiMaster extends Warrior {
151
150
public constructor (
152
- @inject (TYPES .Rank ) @named (" master" ) rank : string // args count = 1
153
- ) {
154
- super (rank );
151
+ @inject (TYPES .Rank ) @named (" master" ) rank : string // args count = 1
152
+ ) {
153
+ super (rank );
155
154
}
156
155
}
157
156
158
- container .bind <string >(TYPES .Rank )
159
- .toConstantValue (" master" )
160
- .whenTargetNamed (" master" );
157
+ container
158
+ .bind <string >(TYPES .Rank )
159
+ .toConstantValue (" master" )
160
+ .whenTargetNamed (" master" );
161
161
```
162
162
163
163
The following should also work:
@@ -172,40 +172,40 @@ class Warrior {
172
172
}
173
173
174
174
interface Weapon {
175
- name: string ;
175
+ name: string ;
176
176
}
177
177
178
178
@injectable ()
179
179
class Katana implements Weapon {
180
- public name: string ;
181
- public constructor () {
182
- this .name = " Katana" ;
183
- }
180
+ public name: string ;
181
+ public constructor () {
182
+ this .name = " Katana" ;
183
+ }
184
184
}
185
185
186
- let TYPES = {
186
+ let TYPES = {
187
187
Rank: " Rank" ,
188
- Weapon: " Weapon"
188
+ Weapon: " Weapon" ,
189
189
};
190
190
191
191
@injectable ()
192
- class SamuraiMaster extends Warrior {
193
- public weapon: Weapon ;
192
+ class SamuraiMaster extends Warrior {
193
+ public weapon: Weapon ;
194
194
public constructor (
195
- @inject (TYPES .Rank ) @named (" master" ) rank : string , // args count = 2
196
- @inject (TYPES .Weapon ) weapon : Weapon
197
- ) {
198
- super (rank );
199
- this .weapon = weapon ;
195
+ @inject (TYPES .Rank ) @named (" master" ) rank : string , // args count = 2
196
+ @inject (TYPES .Weapon ) weapon : Weapon
197
+ ) {
198
+ super (rank );
199
+ this .weapon = weapon ;
200
200
}
201
201
}
202
202
203
203
container .bind <Weapon >(TYPES .Weapon ).to (Katana );
204
204
205
- container . bind < string >( TYPES . Rank )
206
- . toConstantValue ( " master " )
207
- . whenTargetNamed (" master" );
208
-
205
+ container
206
+ . bind < string >( TYPES . Rank )
207
+ . toConstantValue (" master" )
208
+ . whenTargetNamed ( " master " );
209
209
```
210
210
211
211
### WORKAROUND E) Skip Base class ` @injectable ` checks
@@ -215,29 +215,26 @@ Setting the `skipBaseClassChecks` option to `true` for the container will disabl
215
215
``` ts
216
216
// Not injectable
217
217
class UnmanagedBase {
218
- public constructor (
219
- public unmanagedDependency : string
220
- ) {
221
- }
218
+ public constructor (public unmanagedDependency : string ) {}
222
219
}
223
220
224
221
@injectable ()
225
- class InjectableDerived extends UnmanagedBase {
226
- public constructor (
227
- // Any arguments defined here will be injected like normal
228
- ) {
222
+ class InjectableDerived extends UnmanagedBase {
223
+ public constructor () // Any arguments defined here will be injected like normal
224
+ {
229
225
super (" Don't forget me..." );
230
226
}
231
227
}
232
228
233
- const container = new Container ({skipBaseClassChecks: true });
229
+ const container = new Container ({ skipBaseClassChecks: true });
234
230
container .bind (InjectableDerived ).toSelf ();
235
231
```
236
232
237
233
This will work, and you'll be able to use your ` InjectableDerived ` class just like normal, including injecting dependencies from elsewhere in the container through the constructor. The one caveat is that you must make sure your ` UnmanagedBase ` receives the correct arguments.
238
234
239
235
## What can I do when my base class is provided by a third party module?
240
- In some cases, you may get errors about missing annotations in classes
236
+
237
+ In some cases, you may get errors about missing annotations in classes
241
238
provided by a third party module like:
242
239
243
240
> Error: Missing required @injectable annotation in: SamuraiMaster
0 commit comments