@decaf-ts/injectable-decorators 1.6.7 → 1.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +149 -171
- package/dist/injectable-decorators.cjs +159 -75
- package/dist/injectable-decorators.esm.cjs +157 -76
- package/lib/Injectables.cjs +6 -1
- package/lib/Injectables.d.ts +5 -0
- package/lib/constants.cjs +18 -4
- package/lib/constants.d.ts +15 -2
- package/lib/decorators.cjs +105 -47
- package/lib/decorators.d.ts +132 -94
- package/lib/esm/Injectables.d.ts +5 -0
- package/lib/esm/Injectables.js +6 -1
- package/lib/esm/constants.d.ts +15 -2
- package/lib/esm/constants.js +17 -3
- package/lib/esm/decorators.d.ts +132 -94
- package/lib/esm/decorators.js +102 -44
- package/lib/esm/index.d.ts +1 -1
- package/lib/esm/index.js +1 -1
- package/lib/esm/registry.js +6 -4
- package/lib/esm/types.d.ts +40 -3
- package/lib/esm/types.js +1 -1
- package/lib/esm/utils.d.ts +6 -4
- package/lib/esm/utils.js +8 -7
- package/lib/index.cjs +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/registry.cjs +7 -5
- package/lib/types.cjs +1 -1
- package/lib/types.d.ts +40 -3
- package/lib/utils.cjs +11 -9
- package/lib/utils.d.ts +6 -4
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -18,12 +18,6 @@ A lightweight TypeScript dependency injection library that provides decorators f
|
|
|
18
18
|

|
|
19
19
|

|
|
20
20
|
|
|
21
|
-

|
|
22
|
-

|
|
23
|
-

|
|
24
|
-

|
|
25
|
-
|
|
26
|
-
|
|
27
21
|

|
|
28
22
|

|
|
29
23
|

|
|
@@ -82,237 +76,221 @@ Unlike more complex DI frameworks, this library doesn't require extensive config
|
|
|
82
76
|
|
|
83
77
|
### How to Use
|
|
84
78
|
|
|
85
|
-
- [Initial Setup](./tutorials/For%20Developers.md#_initial-setup_)
|
|
86
|
-
- [Installation](./tutorials/For%20Developers.md#installation)
|
|
79
|
+
- [Initial Setup](./workdocs/tutorials/For%20Developers.md#_initial-setup_)
|
|
80
|
+
- [Installation](./workdocs/tutorials/For%20Developers.md#installation)
|
|
87
81
|
|
|
88
82
|
## Basic Usage Examples
|
|
89
83
|
|
|
90
|
-
###
|
|
84
|
+
### 1) Mark a class as injectable and get it from the registry
|
|
91
85
|
|
|
92
|
-
|
|
86
|
+
Description: Define a class with @injectable() so it becomes available through the central registry. Creating with new returns the instance managed by the registry.
|
|
93
87
|
|
|
94
88
|
```typescript
|
|
95
|
-
import
|
|
89
|
+
import 'reflect-metadata';
|
|
90
|
+
import { injectable, Injectables } from 'injectable-decorators';
|
|
96
91
|
|
|
97
92
|
@injectable()
|
|
98
|
-
class
|
|
99
|
-
|
|
100
|
-
console.log(`[LOG]: ${message}`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
error(message: string): void {
|
|
104
|
-
console.error(`[ERROR]: ${message}`);
|
|
105
|
-
}
|
|
93
|
+
class InitialObject {
|
|
94
|
+
doSomething() { return 5; }
|
|
106
95
|
}
|
|
107
96
|
|
|
108
|
-
|
|
109
|
-
|
|
97
|
+
const obj = new InitialObject();
|
|
98
|
+
const same = Injectables.get(InitialObject);
|
|
99
|
+
// obj and same refer to the same instance (singleton by default)
|
|
110
100
|
```
|
|
111
101
|
|
|
112
|
-
###
|
|
102
|
+
### 2) Inject a dependency into a property
|
|
113
103
|
|
|
114
|
-
|
|
104
|
+
Description: Use @inject() on a typed property. The instance is created lazily when the property is first accessed and cached thereafter.
|
|
115
105
|
|
|
116
106
|
```typescript
|
|
117
|
-
import
|
|
118
|
-
import {
|
|
107
|
+
import 'reflect-metadata';
|
|
108
|
+
import { injectable, inject, Injectables } from 'injectable-decorators';
|
|
119
109
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
private logger!: LoggerService;
|
|
110
|
+
@injectable()
|
|
111
|
+
class SomeService { value = 5; }
|
|
123
112
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
this.logger.log(`User ${username} created successfully`);
|
|
128
|
-
}
|
|
113
|
+
class Controller {
|
|
114
|
+
@inject()
|
|
115
|
+
service!: SomeService; // non-null assertion because it's set outside the constructor
|
|
129
116
|
}
|
|
130
117
|
|
|
131
|
-
|
|
132
|
-
//
|
|
118
|
+
const c = new Controller();
|
|
119
|
+
console.log(c.service.value); // 5
|
|
120
|
+
console.log(c.service === Injectables.get(SomeService)); // true
|
|
133
121
|
```
|
|
134
122
|
|
|
135
|
-
###
|
|
123
|
+
### 3) Use a custom category (string) for minification or upcasting
|
|
136
124
|
|
|
137
|
-
|
|
125
|
+
Description: Provide a stable name when class names may change (e.g., minification) or to upcast through a base type.
|
|
138
126
|
|
|
139
127
|
```typescript
|
|
140
|
-
import
|
|
141
|
-
|
|
142
|
-
@injectable('AuthService')
|
|
143
|
-
class AuthenticationService {
|
|
144
|
-
authenticate(username: string, password: string): boolean {
|
|
145
|
-
// Authentication logic...
|
|
146
|
-
return true;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
128
|
+
import 'reflect-metadata';
|
|
129
|
+
import { injectable, inject, singleton } from 'injectable-decorators';
|
|
149
130
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
131
|
+
@singleton()
|
|
132
|
+
class AAA { a = 'aaa'; }
|
|
133
|
+
|
|
134
|
+
@injectable('AAA')
|
|
135
|
+
class BBB extends AAA { b = 'bbb'; }
|
|
136
|
+
|
|
137
|
+
const b = new BBB();
|
|
138
|
+
|
|
139
|
+
class Host {
|
|
140
|
+
@inject()
|
|
141
|
+
repo!: AAA; // resolves to the instance registered under category 'AAA'
|
|
161
142
|
}
|
|
143
|
+
|
|
144
|
+
const h = new Host();
|
|
145
|
+
console.log(h.repo === b); // true
|
|
162
146
|
```
|
|
163
147
|
|
|
164
|
-
###
|
|
148
|
+
### 4) Inject by explicit category (string)
|
|
165
149
|
|
|
166
|
-
|
|
150
|
+
Description: When a different string category was used at registration, pass that string to @inject.
|
|
167
151
|
|
|
168
152
|
```typescript
|
|
169
|
-
import
|
|
153
|
+
import 'reflect-metadata';
|
|
154
|
+
import { inject, singleton } from 'injectable-decorators';
|
|
170
155
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
156
|
+
class DDD { a = 'aaa'; }
|
|
157
|
+
|
|
158
|
+
@singleton('EEE')
|
|
159
|
+
class CCC extends DDD { b = 'bbb'; }
|
|
160
|
+
|
|
161
|
+
const instance = new CCC();
|
|
162
|
+
|
|
163
|
+
class Holder {
|
|
164
|
+
@inject('EEE')
|
|
165
|
+
repo!: CCC;
|
|
181
166
|
}
|
|
182
167
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return config;
|
|
187
|
-
};
|
|
168
|
+
const h = new Holder();
|
|
169
|
+
console.log(h.repo === instance); // true
|
|
170
|
+
```
|
|
188
171
|
|
|
189
|
-
|
|
190
|
-
@inject(undefined, configTransformer)
|
|
191
|
-
private config!: ConfigService;
|
|
172
|
+
### 5) Map one constructor to another and inject by constructor
|
|
192
173
|
|
|
193
|
-
|
|
194
|
-
const apiUrl = this.config.get('apiUrl');
|
|
195
|
-
const timeout = this.config.get('timeout');
|
|
174
|
+
Description: You can register an injectable using another constructor as the category, then inject it by that constructor.
|
|
196
175
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
176
|
+
```typescript
|
|
177
|
+
import 'reflect-metadata';
|
|
178
|
+
import { injectable, inject } from 'injectable-decorators';
|
|
179
|
+
|
|
180
|
+
class Token {}
|
|
181
|
+
|
|
182
|
+
@injectable(Token, { callback: (original) => original })
|
|
183
|
+
class Impl {
|
|
184
|
+
id = 1;
|
|
200
185
|
}
|
|
186
|
+
|
|
187
|
+
class UsesImpl {
|
|
188
|
+
@inject(Token)
|
|
189
|
+
object!: Impl; // injects the instance registered under Token (Impl instance)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const u = new UsesImpl();
|
|
193
|
+
console.log(u.object instanceof Impl); // true
|
|
201
194
|
```
|
|
202
195
|
|
|
203
|
-
###
|
|
196
|
+
### 6) Non-singleton injectables with @onDemand and passing constructor args
|
|
204
197
|
|
|
205
|
-
|
|
198
|
+
Description: Use @onDemand() so each injection produces a fresh instance. You can pass args for construction via @inject({ args }).
|
|
206
199
|
|
|
207
200
|
```typescript
|
|
208
|
-
import
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
throw new Error('Database connection not available');
|
|
225
|
-
}
|
|
226
|
-
return this.db.query(sql);
|
|
227
|
-
}
|
|
201
|
+
import 'reflect-metadata';
|
|
202
|
+
import { onDemand, inject } from 'injectable-decorators';
|
|
203
|
+
|
|
204
|
+
@onDemand()
|
|
205
|
+
class FreshObject {
|
|
206
|
+
constructor(public a?: string, public b?: string) {}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
class ParentA {
|
|
210
|
+
@inject()
|
|
211
|
+
fresh!: FreshObject; // new instance per parent
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
class ParentB {
|
|
215
|
+
@inject({ args: ['x', 'y'] })
|
|
216
|
+
fresh!: FreshObject; // passes constructor args to on-demand instance
|
|
228
217
|
}
|
|
218
|
+
|
|
219
|
+
const p1 = new ParentA();
|
|
220
|
+
const p2 = new ParentA();
|
|
221
|
+
console.log(p1.fresh !== p2.fresh); // true
|
|
222
|
+
|
|
223
|
+
const p3 = new ParentB();
|
|
224
|
+
console.log([p3.fresh.a, p3.fresh.b]); // ['x','y']
|
|
229
225
|
```
|
|
230
226
|
|
|
231
|
-
###
|
|
227
|
+
### 7) Transform an injected value
|
|
232
228
|
|
|
233
|
-
|
|
229
|
+
Description: Modify the resolved instance before assignment using a transformer.
|
|
234
230
|
|
|
235
231
|
```typescript
|
|
236
|
-
import
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
get<T>(name: string, ...args: any[]): T | undefined {
|
|
247
|
-
console.log(`Getting injectable: ${name}`);
|
|
248
|
-
return this.defaultRegistry.get<T>(name, ...args);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
register<T>(constructor: any, ...args: any[]): void {
|
|
252
|
-
console.log(`Registering injectable: ${args[0] || constructor.name}`);
|
|
253
|
-
return this.defaultRegistry.register(constructor, ...args);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
build<T>(obj: Record<string, any>, ...args: any[]): T {
|
|
257
|
-
console.log(`Building injectable: ${obj.name}`);
|
|
258
|
-
return this.defaultRegistry.build<T>(obj, ...args);
|
|
259
|
-
}
|
|
232
|
+
import 'reflect-metadata';
|
|
233
|
+
import { injectable, inject } from 'injectable-decorators';
|
|
234
|
+
|
|
235
|
+
@injectable('SomeOtherObject')
|
|
236
|
+
class SomeOtherObject { value() { return 10; } }
|
|
237
|
+
|
|
238
|
+
class Controller {
|
|
239
|
+
@inject({ transformer: (obj: SomeOtherObject, c: Controller) => '1' })
|
|
240
|
+
repo!: SomeOtherObject | string;
|
|
260
241
|
}
|
|
261
242
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const customRegistry = new LoggingRegistry(new InjectableRegistryImp());
|
|
265
|
-
Injectables.setRegistry(customRegistry);
|
|
243
|
+
const c = new Controller();
|
|
244
|
+
console.log(c.repo); // '1'
|
|
266
245
|
```
|
|
267
246
|
|
|
268
|
-
###
|
|
247
|
+
### 8) Registry operations: reset and swapping registry
|
|
269
248
|
|
|
270
|
-
|
|
249
|
+
Description: Reset clears all registrations. Swapping the registry replaces the storage, losing previous entries.
|
|
271
250
|
|
|
272
251
|
```typescript
|
|
273
|
-
import { Injectables } from 'injectable-decorators';
|
|
252
|
+
import { Injectables, InjectableRegistryImp } from 'injectable-decorators';
|
|
253
|
+
|
|
254
|
+
// ensure something is registered
|
|
255
|
+
Injectables.get('SomeOtherObject');
|
|
274
256
|
|
|
275
|
-
//
|
|
257
|
+
// swap to a fresh registry
|
|
258
|
+
Injectables.setRegistry(new InjectableRegistryImp());
|
|
259
|
+
console.log(Injectables.get('SomeOtherObject')); // undefined
|
|
260
|
+
|
|
261
|
+
// reset to a new empty default registry
|
|
276
262
|
Injectables.reset();
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### 9) Singleton vs onDemand convenience decorators
|
|
266
|
+
|
|
267
|
+
Description: Prefer @singleton() to force single instance, or @onDemand() for new instance per retrieval.
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import { singleton, onDemand } from 'injectable-decorators';
|
|
271
|
+
|
|
272
|
+
@singleton()
|
|
273
|
+
class OneOnly {}
|
|
277
274
|
|
|
278
|
-
|
|
279
|
-
|
|
275
|
+
@onDemand()
|
|
276
|
+
class Many {}
|
|
280
277
|
```
|
|
281
278
|
|
|
282
|
-
###
|
|
279
|
+
### 10) Utility helpers and constants
|
|
283
280
|
|
|
284
|
-
|
|
281
|
+
Description: Generate reflection keys and understand default config.
|
|
285
282
|
|
|
286
283
|
```typescript
|
|
287
|
-
import {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
instance.setLogLevel('debug');
|
|
292
|
-
instance.enableConsoleOutput(true);
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
@injectable(undefined, false, setupLogger)
|
|
296
|
-
class LoggerService {
|
|
297
|
-
private logLevel: string = 'info';
|
|
298
|
-
private consoleOutput: boolean = false;
|
|
299
|
-
|
|
300
|
-
setLogLevel(level: string): void {
|
|
301
|
-
this.logLevel = level;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
enableConsoleOutput(enabled: boolean): void {
|
|
305
|
-
this.consoleOutput = enabled;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
log(message: string): void {
|
|
309
|
-
if (this.consoleOutput) {
|
|
310
|
-
console.log(`[${this.logLevel.toUpperCase()}]: ${message}`);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
284
|
+
import { getInjectKey } from 'injectable-decorators';
|
|
285
|
+
|
|
286
|
+
console.log(getInjectKey('injectable')); // "inject.db.injectable"
|
|
287
|
+
console.log(getInjectKey('inject')); // "inject.db.inject"
|
|
314
288
|
```
|
|
315
289
|
|
|
290
|
+
Notes:
|
|
291
|
+
- Always include `import 'reflect-metadata'` once in your app before using decorators.
|
|
292
|
+
- VERSION is exported as a string placeholder defined at build time.
|
|
293
|
+
|
|
316
294
|
|
|
317
295
|
### Related
|
|
318
296
|
|