or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

decorators.mddependency-container.mdfactories.mdindex.mdlazy-loading.mdlifecycle-management.mdproviders.md

providers.mddocs/

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

```