0
# Provider System
1
2
Flexible provider system for registering dependencies using different patterns including class constructors, factory functions, concrete values, and token aliases. Includes comprehensive type guards for runtime provider type checking.
3
4
## Capabilities
5
6
### Provider Types
7
8
Union type encompassing all available provider patterns for maximum flexibility in dependency registration.
9
10
```typescript { .api }
11
/**
12
* Union type of all provider types
13
* Enables flexible dependency registration patterns
14
*/
15
type Provider<T> = ClassProvider<T> | FactoryProvider<T> | ValueProvider<T> | TokenProvider<T>;
16
17
/**
18
* Type guard to check if value is any provider type
19
* @param provider - Value to check
20
* @returns True if value is a provider
21
*/
22
function isProvider<T>(provider: any): provider is Provider<T>;
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
const classProvider: Provider<UserService> = { useClass: UserService };
29
const factoryProvider: Provider<Logger> = {
30
useFactory: (container) => new Logger(container.resolve("LogLevel"))
31
};
32
33
if (isProvider(someValue)) {
34
container.register("Service", someValue);
35
}
36
```
37
38
### Class Provider
39
40
Provider that uses a class constructor to create instances, supporting both regular constructors and delayed constructors for lazy loading.
41
42
```typescript { .api }
43
/**
44
* Provider using class constructor for instance creation
45
* Supports both regular and delayed constructors
46
*/
47
interface ClassProvider<T> {
48
useClass: constructor<T> | DelayedConstructor<T>;
49
}
50
51
/**
52
* Type guard for class providers
53
* @param provider - Provider to check
54
* @returns True if provider is ClassProvider
55
*/
56
function isClassProvider<T>(provider: any): provider is ClassProvider<T>;
57
```
58
59
**Usage Examples:**
60
61
```typescript
62
// Basic class provider
63
const userServiceProvider: ClassProvider<UserService> = {
64
useClass: UserService
65
};
66
67
// With delayed constructor for circular dependencies
68
const delayedProvider: ClassProvider<CircularService> = {
69
useClass: delay(() => CircularService)
70
};
71
72
container.register("UserService", userServiceProvider);
73
74
// Type guard usage
75
if (isClassProvider(provider)) {
76
console.log("Using class:", provider.useClass.name);
77
}
78
```
79
80
### Factory Provider
81
82
Provider that uses a factory function to create instances, providing access to the dependency container for complex construction logic.
83
84
```typescript { .api }
85
/**
86
* Provider using factory function for instance creation
87
* Factory receives dependency container for complex construction
88
*/
89
interface FactoryProvider<T> {
90
useFactory: (dependencyContainer: DependencyContainer) => T;
91
}
92
93
/**
94
* Type guard for factory providers
95
* @param provider - Provider to check
96
* @returns True if provider is FactoryProvider
97
*/
98
function isFactoryProvider<T>(provider: any): provider is FactoryProvider<T>;
99
```
100
101
**Usage Examples:**
102
103
```typescript
104
// Database connection factory
105
const dbProvider: FactoryProvider<Database> = {
106
useFactory: (container) => {
107
const config = container.resolve<DatabaseConfig>("DatabaseConfig");
108
const logger = container.resolve<Logger>("Logger");
109
return new Database(config.connectionString, logger);
110
}
111
};
112
113
// Conditional factory
114
const loggerProvider: FactoryProvider<Logger> = {
115
useFactory: (container) => {
116
const env = container.resolve<string>("Environment");
117
return env === "production"
118
? new ProductionLogger()
119
: new DevelopmentLogger();
120
}
121
};
122
123
container.register("Database", dbProvider);
124
125
if (isFactoryProvider(provider)) {
126
const instance = provider.useFactory(container);
127
}
128
```
129
130
### Value Provider
131
132
Provider that directly provides a concrete value or instance, useful for configuration objects, primitives, and pre-constructed instances.
133
134
```typescript { .api }
135
/**
136
* Provider using concrete value or pre-constructed instance
137
* Perfect for configuration, primitives, and shared instances
138
*/
139
interface ValueProvider<T> {
140
useValue: T;
141
}
142
143
/**
144
* Type guard for value providers
145
* @param provider - Provider to check
146
* @returns True if provider is ValueProvider
147
*/
148
function isValueProvider<T>(provider: any): provider is ValueProvider<T>;
149
```
150
151
**Usage Examples:**
152
153
```typescript
154
// Configuration object
155
const configProvider: ValueProvider<AppConfig> = {
156
useValue: {
157
apiUrl: "https://api.example.com",
158
timeout: 5000,
159
retries: 3
160
}
161
};
162
163
// Primitive values
164
const portProvider: ValueProvider<number> = {
165
useValue: 8080
166
};
167
168
// Pre-constructed instance
169
const existingLogger = new Logger("app");
170
const loggerProvider: ValueProvider<Logger> = {
171
useValue: existingLogger
172
};
173
174
container.register("AppConfig", configProvider);
175
container.register("Port", portProvider);
176
177
if (isValueProvider(provider)) {
178
console.log("Direct value:", provider.useValue);
179
}
180
```
181
182
### Token Provider
183
184
Provider that aliases one injection token to another, enabling interface-to-implementation mapping and token redirection.
185
186
```typescript { .api }
187
/**
188
* Provider that aliases one token to another
189
* Enables interface-to-implementation mapping
190
*/
191
interface TokenProvider<T> {
192
useToken: InjectionToken<T>;
193
}
194
195
/**
196
* Type guard for token providers
197
* @param provider - Provider to check
198
* @returns True if provider is TokenProvider
199
*/
200
function isTokenProvider<T>(provider: any): provider is TokenProvider<T>;
201
```
202
203
**Usage Examples:**
204
205
```typescript
206
// Interface to implementation mapping
207
container.register("PostgresUserRepo", PostgresUserRepository);
208
const repoProvider: TokenProvider<IUserRepository> = {
209
useToken: "PostgresUserRepo"
210
};
211
container.register("IUserRepository", repoProvider);
212
213
// Environment-based aliasing
214
const dbProvider: TokenProvider<IDatabase> = {
215
useToken: process.env.NODE_ENV === "test" ? "MockDatabase" : "PostgresDatabase"
216
};
217
218
// Class token aliasing
219
const serviceProvider: TokenProvider<IUserService> = {
220
useToken: UserService
221
};
222
223
if (isTokenProvider(provider)) {
224
console.log("Redirects to token:", provider.useToken);
225
}
226
```
227
228
### Injection Token System
229
230
Comprehensive token system supporting multiple token types with utility functions for token type checking and metadata handling.
231
232
```typescript { .api }
233
/**
234
* Union type for all supported injection token types
235
* Supports classes, strings, symbols, and delayed constructors
236
*/
237
type InjectionToken<T> = constructor<T> | string | symbol | DelayedConstructor<T>;
238
239
/**
240
* Type guard for normal tokens (string | symbol)
241
* @param token - Token to check
242
* @returns True if token is string or symbol
243
*/
244
function isNormalToken(token: any): token is string | symbol;
245
246
/**
247
* Type guard for constructor tokens
248
* @param token - Token to check
249
* @returns True if token is constructor function
250
*/
251
function isConstructorToken(token: any): token is constructor<any>;
252
```
253
254
**Usage Examples:**
255
256
```typescript
257
// Different token types
258
const stringToken: InjectionToken<UserService> = "UserService";
259
const symbolToken: InjectionToken<Logger> = Symbol("Logger");
260
const classToken: InjectionToken<Database> = Database;
261
const delayedToken: InjectionToken<CircularService> = delay(() => CircularService);
262
263
// Token checking
264
if (isNormalToken(token)) {
265
console.log("String or symbol token:", token.toString());
266
}
267
268
if (isConstructorToken(token)) {
269
console.log("Constructor token:", token.name);
270
}
271
272
// Registration with different token types
273
container.register(stringToken, UserService);
274
container.register(symbolToken, ConsoleLogger);
275
container.register(classToken, { useClass: PostgresDatabase });
276
```
277
278
### Token Descriptors
279
280
Advanced token metadata system for complex injection scenarios with multiple dependencies and transformations.
281
282
```typescript { .api }
283
/**
284
* Token descriptor with metadata for complex injection
285
* Used internally for parameter decoration metadata
286
*/
287
interface TokenDescriptor {
288
token: InjectionToken<any>;
289
multiple: boolean;
290
isOptional?: boolean;
291
}
292
293
/**
294
* Transform descriptor for parameter transformation
295
* Contains transformation token and arguments
296
*/
297
interface TransformDescriptor {
298
token: InjectionToken<any>;
299
transform: InjectionToken<Transform<any, any>>;
300
transformArgs: any[];
301
}
302
303
/**
304
* Type guard for token descriptors
305
* @param descriptor - Descriptor to check
306
* @returns True if descriptor is TokenDescriptor
307
*/
308
function isTokenDescriptor(descriptor: any): descriptor is TokenDescriptor;
309
310
/**
311
* Type guard for transform descriptors
312
* @param descriptor - Descriptor to check
313
* @returns True if descriptor is TransformDescriptor
314
*/
315
function isTransformDescriptor(descriptor: any): descriptor is TransformDescriptor;
316
```
317
318
**Usage Examples:**
319
320
```typescript
321
// Token descriptors are typically used internally
322
// but can be useful for advanced scenarios
323
324
const descriptor: TokenDescriptor = {
325
token: "UserService",
326
multiple: false,
327
isOptional: true
328
};
329
330
const transformDescriptor: TransformDescriptor = {
331
token: "ConfigValues",
332
transform: "StringToNumberTransform",
333
transformArgs: ["radix", 10]
334
};
335
336
// Type checking
337
if (isTokenDescriptor(someDescriptor)) {
338
console.log("Token:", someDescriptor.token);
339
console.log("Multiple:", someDescriptor.multiple);
340
}
341
342
if (isTransformDescriptor(someDescriptor)) {
343
console.log("Transform token:", someDescriptor.transform);
344
console.log("Transform args:", someDescriptor.transformArgs);
345
}
346
```
347
348
## Types
349
350
```typescript { .api }
351
// Core provider union type
352
type Provider<T> = ClassProvider<T> | FactoryProvider<T> | ValueProvider<T> | TokenProvider<T>;
353
354
// Individual provider interfaces
355
interface ClassProvider<T> {
356
useClass: constructor<T> | DelayedConstructor<T>;
357
}
358
359
interface FactoryProvider<T> {
360
useFactory: (dependencyContainer: DependencyContainer) => T;
361
}
362
363
interface ValueProvider<T> {
364
useValue: T;
365
}
366
367
interface TokenProvider<T> {
368
useToken: InjectionToken<T>;
369
}
370
371
// Token system types
372
type InjectionToken<T> = constructor<T> | string | symbol | DelayedConstructor<T>;
373
374
interface TokenDescriptor {
375
token: InjectionToken<any>;
376
multiple: boolean;
377
isOptional?: boolean;
378
}
379
380
interface TransformDescriptor {
381
token: InjectionToken<any>;
382
transform: InjectionToken<Transform<any, any>>;
383
transformArgs: any[];
384
}
385
386
// Constructor type
387
type constructor<T> = {new (...args: any[]): T};
388
389
// Transform interface
390
interface Transform<TIn, TOut> {
391
transform(incoming: TIn, ...args: any[]): TOut;
392
}
393
```