0
# Qualifiers and Parameters
1
2
Type-safe dependency identification and parameter injection for complex dependency graphs and runtime configuration.
3
4
## Capabilities
5
6
### Qualifier System
7
8
Use qualifiers to differentiate between multiple instances of the same type.
9
10
```javascript { .api }
11
interface Qualifier {
12
/**
13
* Qualifier value for unique identification
14
*/
15
value: any;
16
}
17
18
/**
19
* Create named string-based qualifier
20
* @param name - Qualifier name
21
* @returns StringQualifier instance
22
*/
23
function named(name: string): Qualifier;
24
25
/**
26
* Create type-based qualifier using generics
27
* @returns TypeQualifier instance
28
*/
29
function named<T>(): Qualifier;
30
31
/**
32
* Create string qualifier (alias for named)
33
* @param name - Qualifier name
34
* @returns StringQualifier instance
35
*/
36
function qualifier(name: string): Qualifier;
37
38
/**
39
* Create type qualifier (alias for named)
40
* @returns TypeQualifier instance
41
*/
42
function qualifier<T>(): Qualifier;
43
44
/**
45
* Short qualifier function for string
46
* @param name - Qualifier name
47
* @returns StringQualifier instance
48
*/
49
function _q(name: string): Qualifier;
50
51
/**
52
* Short qualifier function for type
53
* @returns TypeQualifier instance
54
*/
55
function _q<T>(): Qualifier;
56
```
57
58
**Usage Examples:**
59
60
```javascript
61
import { module, named, qualifier, _q } from "koin-core";
62
63
const databaseModule = module((builder) => {
64
// Multiple database connections with qualifiers
65
builder.single(named("primary"), () =>
66
new DatabaseConnection("primary-db:5432")
67
);
68
69
builder.single(named("secondary"), () =>
70
new DatabaseConnection("secondary-db:5432")
71
);
72
73
builder.single(named("cache"), () =>
74
new DatabaseConnection("redis:6379")
75
);
76
77
// Multiple loggers with type qualifiers
78
builder.single(qualifier("console"), () => new ConsoleLogger());
79
builder.single(qualifier("file"), () => new FileLogger("/var/log/app.log"));
80
81
// Short syntax qualifiers
82
builder.factory(_q("temp"), () => new TemporaryStorage());
83
builder.factory(_q("persistent"), () => new PersistentStorage());
84
});
85
86
// Using qualified dependencies
87
class UserService extends KoinComponent {
88
constructor() {
89
super();
90
this.primaryDb = this.get(named("primary")); // Primary database
91
this.cacheDb = this.get(named("cache")); // Cache database
92
this.logger = this.get(qualifier("file")); // File logger
93
this.storage = this.get(_q("persistent")); // Persistent storage
94
}
95
}
96
```
97
98
### Qualifier Types
99
100
Different qualifier implementations for various identification strategies.
101
102
```javascript { .api }
103
/**
104
* String-based qualifier for named identification
105
*/
106
class StringQualifier implements Qualifier {
107
constructor(name: string);
108
value: string;
109
toString(): string;
110
}
111
112
/**
113
* Type-based qualifier for class-based identification
114
*/
115
class TypeQualifier implements Qualifier {
116
constructor(type: any);
117
value: any;
118
toString(): string;
119
}
120
```
121
122
**Usage Examples:**
123
124
```javascript
125
import { StringQualifier, TypeQualifier } from "koin-core";
126
127
// Manual qualifier creation
128
const primaryQualifier = new StringQualifier("primary");
129
const typeQualifier = new TypeQualifier(DatabaseService);
130
131
// Using in module definitions
132
const manualModule = module((builder) => {
133
builder.single(primaryQualifier, () => new PrimaryService());
134
builder.single(typeQualifier, () => new DatabaseService());
135
});
136
137
// Qualifier comparison and identification
138
function logQualifier(qualifier) {
139
console.log(`Qualifier: ${qualifier.toString()}`);
140
console.log(`Value: ${qualifier.value}`);
141
}
142
143
logQualifier(named("test")); // "Qualifier: test, Value: test"
144
logQualifier(named<UserService>()); // "Qualifier: UserService, Value: [class]"
145
```
146
147
### Parameter System
148
149
Pass parameters during dependency resolution for dynamic instance creation.
150
151
```javascript { .api }
152
/**
153
* Create parameters holder with ordered values
154
* @param parameters - Parameter values in injection order
155
* @returns ParametersHolder for injection
156
*/
157
function parametersOf(...parameters: any[]): ParametersHolder;
158
159
/**
160
* Create indexed parameter array for array-like access
161
* @param parameters - Parameter values
162
* @returns ParametersHolder with indexed access
163
*/
164
function parameterArrayOf(...parameters: any[]): ParametersHolder;
165
166
/**
167
* Create parameter set for type-based parameter access
168
* @param parameters - Parameter values
169
* @returns ParametersHolder with type-based access
170
*/
171
function parameterSetOf(...parameters: any[]): ParametersHolder;
172
173
/**
174
* Create empty parameters holder
175
* @returns Empty ParametersHolder
176
*/
177
function emptyParametersHolder(): ParametersHolder;
178
```
179
180
**Usage Examples:**
181
182
```javascript
183
import {
184
parametersOf,
185
parameterArrayOf,
186
parameterSetOf,
187
emptyParametersHolder
188
} from "koin-core";
189
190
// Different parameter creation methods
191
const orderedParams = parametersOf("localhost", 5432, "myapp", true);
192
const arrayParams = parameterArrayOf("item1", "item2", "item3");
193
const typedParams = parameterSetOf(new Date(), "config", 100);
194
const noParams = emptyParametersHolder();
195
196
// Usage in dependency injection
197
class DatabaseService extends KoinComponent {
198
async connect(host, port, database, ssl = false) {
199
const connection = this.get(named("dynamic"), () =>
200
parametersOf(host, port, database, ssl)
201
);
202
203
return await connection.connect();
204
}
205
}
206
```
207
208
### Parameter Access
209
210
Access and retrieve parameters within dependency definitions.
211
212
```javascript { .api }
213
class ParametersHolder {
214
/**
215
* Get parameter by index with optional type checking
216
* @param index - Parameter index (0-based)
217
* @param clazz - Optional expected parameter type
218
* @returns Parameter value of type T
219
* @throws NoParameterFoundException if index out of bounds
220
*/
221
elementAt<T>(index: number, clazz?: new (...args: any[]) => T): T;
222
223
/**
224
* Get parameter by type - returns first matching type
225
* @returns Parameter value of type T
226
* @throws NoParameterFoundException if type not found
227
*/
228
get<T>(): T;
229
230
/**
231
* Check if parameters are empty
232
* @returns true if no parameters
233
*/
234
isEmpty(): boolean;
235
236
/**
237
* Check if parameters exist
238
* @returns true if parameters are present
239
*/
240
isNotEmpty(): boolean;
241
242
/**
243
* Get parameter count
244
* @returns Number of parameters
245
*/
246
size(): number;
247
248
/**
249
* Get parameter values as array
250
* @returns Array of all parameter values
251
*/
252
values(): any[];
253
}
254
```
255
256
**Usage Examples:**
257
258
```javascript
259
import { module, parametersOf } from "koin-core";
260
261
// Module with parameter-accepting definitions
262
const dynamicModule = module((builder) => {
263
builder.factory((scope, params) => {
264
// Access parameters by index
265
const host = params.elementAt(0); // string
266
const port = params.elementAt(1); // number
267
const ssl = params.elementAt(2); // boolean
268
269
return new DatabaseConnection(host, port, ssl);
270
});
271
272
builder.single((scope, params) => {
273
// Access parameters by type
274
const config = params.get(); // ConfigObject
275
const logger = params.get(); // Logger
276
277
return new ConfigurationService(config, logger);
278
});
279
280
builder.factory((scope, params) => {
281
// Parameter validation and defaults
282
if (params.isEmpty()) {
283
return new DefaultApiClient();
284
}
285
286
const baseUrl = params.size() > 0 ? params.elementAt(0) : "https://api.default.com";
287
const timeout = params.size() > 1 ? params.elementAt(1) : 5000;
288
289
return new ApiClient(baseUrl, timeout);
290
});
291
});
292
293
// Using parameters in injection
294
class ServiceManager extends KoinComponent {
295
async createDatabaseConnection(host, port, useSSL) {
296
const connection = this.get(named("database"), () =>
297
parametersOf(host, port, useSSL)
298
);
299
300
return connection;
301
}
302
303
async createConfiguredService() {
304
const config = new ConfigObject({ env: "production" });
305
const logger = new FileLogger("/var/log/service.log");
306
307
const service = this.get(named("configured"), () =>
308
parametersOf(config, logger)
309
);
310
311
return service;
312
}
313
}
314
```
315
316
### Destructuring Support
317
318
Use destructuring syntax for convenient parameter access.
319
320
```javascript { .api }
321
class ParametersHolder {
322
/**
323
* Destructuring support - get first parameter
324
* @returns First parameter value
325
*/
326
component1<T>(): T;
327
328
/**
329
* Destructuring support - get second parameter
330
* @returns Second parameter value
331
*/
332
component2<T>(): T;
333
334
/**
335
* Destructuring support - get third parameter
336
* @returns Third parameter value
337
*/
338
component3<T>(): T;
339
340
/**
341
* Destructuring support - get fourth parameter
342
* @returns Fourth parameter value
343
*/
344
component4<T>(): T;
345
346
/**
347
* Destructuring support - get fifth parameter
348
* @returns Fifth parameter value
349
*/
350
component5<T>(): T;
351
}
352
```
353
354
**Usage Examples:**
355
356
```javascript
357
import { module, parametersOf } from "koin-core";
358
359
const destructuringModule = module((builder) => {
360
builder.factory((scope, params) => {
361
// Destructuring parameter access
362
const host = params.component1(); // First parameter
363
const port = params.component2(); // Second parameter
364
const database = params.component3(); // Third parameter
365
const username = params.component4(); // Fourth parameter
366
const password = params.component5(); // Fifth parameter
367
368
return new DatabaseConfig(host, port, database, username, password);
369
});
370
371
builder.single((scope, params) => {
372
// Mixed access patterns
373
const [baseUrl, timeout] = [params.component1(), params.component2()];
374
const retries = params.elementAt(2, Number); // Type-checked access
375
376
return new HttpClientConfig(baseUrl, timeout, retries);
377
});
378
});
379
380
// Usage with destructuring
381
class ConfigurationManager extends KoinComponent {
382
async setupDatabase() {
383
const dbConfig = this.get(named("database"), () =>
384
parametersOf(
385
"prod-db.example.com",
386
5432,
387
"production_db",
388
"admin",
389
"secure_password"
390
)
391
);
392
393
return dbConfig;
394
}
395
}
396
```
397
398
### Parameter Validation and Error Handling
399
400
Handle parameter-related errors and validation.
401
402
```javascript { .api }
403
/**
404
* Exception thrown when required parameter is not found
405
*/
406
class NoParameterFoundException extends Error {
407
constructor(message: string);
408
}
409
410
/**
411
* Exception thrown when parameter type doesn't match expected
412
*/
413
class DefinitionParameterException extends Error {
414
constructor(message: string);
415
}
416
```
417
418
**Usage Examples:**
419
420
```javascript
421
import {
422
module,
423
parametersOf,
424
NoParameterFoundException,
425
DefinitionParameterException
426
} from "koin-core";
427
428
const validatedModule = module((builder) => {
429
builder.factory((scope, params) => {
430
try {
431
// Validate required parameters
432
if (params.isEmpty()) {
433
throw new DefinitionParameterException("Database parameters required");
434
}
435
436
if (params.size() < 2) {
437
throw new DefinitionParameterException("Host and port parameters required");
438
}
439
440
const host = params.elementAt(0);
441
const port = params.elementAt(1);
442
443
// Type validation
444
if (typeof host !== 'string') {
445
throw new DefinitionParameterException("Host must be string");
446
}
447
448
if (typeof port !== 'number') {
449
throw new DefinitionParameterException("Port must be number");
450
}
451
452
return new DatabaseConnection(host, port);
453
454
} catch (error) {
455
if (error instanceof NoParameterFoundException) {
456
console.error("Missing required parameter:", error.message);
457
return new DatabaseConnection("localhost", 5432); // Default fallback
458
}
459
throw error;
460
}
461
});
462
});
463
464
// Safe parameter access
465
class SafeServiceManager extends KoinComponent {
466
async createConnection(host, port) {
467
try {
468
const connection = this.get(named("validated"), () =>
469
parametersOf(host, port)
470
);
471
return connection;
472
} catch (error) {
473
if (error instanceof DefinitionParameterException) {
474
console.error("Parameter validation failed:", error.message);
475
// Handle gracefully or re-throw
476
throw new Error(`Failed to create connection: ${error.message}`);
477
}
478
throw error;
479
}
480
}
481
}
482
```
483
484
## Types
485
486
```javascript { .api }
487
/** Function type for parameter definitions */
488
type ParametersDefinition = () => ParametersHolder;
489
490
/** Qualifier value type - can be any type */
491
type QualifierValue = any;
492
493
/** String-based qualifier implementation */
494
class StringQualifier implements Qualifier {
495
value: string;
496
constructor(name: string);
497
}
498
499
/** Type-based qualifier implementation */
500
class TypeQualifier implements Qualifier {
501
value: any;
502
constructor(type: any);
503
}
504
505
/** Parameter holder for dependency injection */
506
class ParametersHolder {
507
values(): any[];
508
elementAt<T>(index: number, clazz?: new (...args: any[]) => T): T;
509
get<T>(): T;
510
isEmpty(): boolean;
511
isNotEmpty(): boolean;
512
size(): number;
513
component1<T>(): T;
514
component2<T>(): T;
515
component3<T>(): T;
516
component4<T>(): T;
517
component5<T>(): T;
518
}
519
520
/** Exception for missing parameters */
521
class NoParameterFoundException extends Error {
522
constructor(message: string);
523
}
524
525
/** Exception for parameter definition errors */
526
class DefinitionParameterException extends Error {
527
constructor(message: string);
528
}
529
```