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

lazy-loading.mddocs/

0

# Lazy Loading

1

2

Lazy initialization utilities for circular dependency resolution, delayed constructor instantiation, and performance optimization through deferred object creation.

3

4

## Capabilities

5

6

### Delayed Constructor

7

8

Proxy-based class for lazy loading that defers constructor resolution until the instance is actually used.

9

10

```typescript { .api }

11

/**

12

* Proxy-based delayed constructor for lazy loading

13

* Defers constructor resolution until instance creation

14

*/

15

class DelayedConstructor<T> {

16

/**

17

* Creates proxy instance that delays object creation

18

* @param createObject - Function to create the actual instance

19

* @returns Proxy instance of type T

20

*/

21

createProxy(createObject: (ctor: constructor<T>) => T): T;

22

}

23

```

24

25

**Usage Examples:**

26

27

```typescript

28

// Manual DelayedConstructor usage (typically internal)

29

const delayedUserService = new DelayedConstructor<UserService>();

30

31

const userServiceProxy = delayedUserService.createProxy((ctor) => {

32

// This function is called only when the instance is first accessed

33

console.log("Creating UserService instance");

34

return new ctor(logger, database);

35

});

36

37

// userServiceProxy acts like UserService but creation is deferred

38

// until first method call or property access

39

```

40

41

### Delay Function

42

43

Primary utility function for creating delayed constructors that resolve circular dependencies and enable lazy instantiation.

44

45

```typescript { .api }

46

/**

47

* Creates delayed constructor for lazy loading and circular dependency resolution

48

* Constructor function is provided via callback, enabling forward references

49

* @param wrappedConstructor - Function returning the actual constructor

50

* @returns DelayedConstructor instance for lazy instantiation

51

*/

52

function delay<T>(wrappedConstructor: () => constructor<T>): DelayedConstructor<T>;

53

```

54

55

**Usage Examples:**

56

57

```typescript

58

// Circular dependency resolution

59

class UserService {

60

constructor(

61

private orderService: OrderService,

62

private logger: Logger

63

) {}

64

65

getUserOrders(userId: string) {

66

return this.orderService.getOrdersByUser(userId);

67

}

68

}

69

70

class OrderService {

71

constructor(

72

private userService: UserService, // Circular dependency!

73

private database: Database

74

) {}

75

76

getOrdersByUser(userId: string) {

77

const user = this.userService.getUser(userId);

78

return this.database.getOrders({ userId: user.id });

79

}

80

81

getUser(userId: string) {

82

// This creates a circular call, but delay() resolves it

83

return this.userService.getUser(userId);

84

}

85

}

86

87

// Register with delayed constructor to break circular dependency

88

container.register("UserService", UserService);

89

container.register("OrderService", {

90

useClass: delay(() => OrderService) // Delay resolves circular reference

91

});

92

93

// Forward reference resolution

94

// Useful when classes are defined in dependency order

95

container.register("EarlyService", {

96

useClass: delay(() => LateService) // LateService defined later in file

97

});

98

99

@injectable()

100

class EarlyService {

101

constructor(private lateService: LateService) {}

102

}

103

104

// LateService defined after EarlyService

105

@injectable()

106

class LateService {

107

doSomething() {

108

return "Late service action";

109

}

110

}

111

```

112

113

### Lazy Loading Patterns

114

115

Common patterns and best practices for implementing lazy loading with TSyringe.

116

117

**Usage Examples:**

118

119

```typescript

120

// Lazy singleton with expensive initialization

121

const expensiveSingletonDelay = delay(() => {

122

// This code only runs when the service is first resolved

123

console.log("Initializing expensive singleton");

124

125

return class ExpensiveService {

126

private data: LargeDataSet;

127

128

constructor() {

129

// Expensive initialization

130

this.data = this.loadLargeDataSet();

131

}

132

133

private loadLargeDataSet(): LargeDataSet {

134

// Simulate expensive operation

135

return new LargeDataSet();

136

}

137

138

processData(input: any) {

139

return this.data.process(input);

140

}

141

};

142

});

143

144

container.register("ExpensiveService", {

145

useClass: expensiveSingletonDelay

146

}, { lifecycle: Lifecycle.Singleton });

147

148

// Conditional lazy loading

149

const conditionalServiceDelay = delay(() => {

150

// Determine service type at resolution time

151

const env = process.env.NODE_ENV;

152

153

if (env === "production") {

154

return ProductionService;

155

} else if (env === "test") {

156

return MockService;

157

} else {

158

return DevelopmentService;

159

}

160

});

161

162

container.register("ConditionalService", {

163

useClass: conditionalServiceDelay

164

});

165

166

// Plugin system with lazy loading

167

interface Plugin {

168

name: string;

169

execute(): void;

170

}

171

172

// Plugins are loaded only when needed

173

const pluginDelays = [

174

delay(() => class EmailPlugin implements Plugin {

175

name = "email";

176

execute() { console.log("Sending email"); }

177

}),

178

delay(() => class SmsPlugin implements Plugin {

179

name = "sms";

180

execute() { console.log("Sending SMS"); }

181

}),

182

delay(() => class PushPlugin implements Plugin {

183

name = "push";

184

execute() { console.log("Sending push notification"); }

185

})

186

];

187

188

// Register plugins lazily

189

pluginDelays.forEach((pluginDelay, index) => {

190

container.register(`Plugin${index}`, { useClass: pluginDelay });

191

});

192

193

// Lazy dependency injection with optional dependencies

194

@injectable()

195

class ServiceWithOptionalDependencies {

196

constructor(

197

private required: RequiredService,

198

@inject("OptionalService") private optional?: OptionalService

199

) {}

200

201

performAction() {

202

this.required.doRequiredWork();

203

204

// Optional service is only resolved if registered

205

if (this.optional) {

206

this.optional.doOptionalWork();

207

}

208

}

209

}

210

211

// Register optional service with delay for performance

212

container.register("OptionalService", {

213

useClass: delay(() => {

214

// Only load this service if it's actually used

215

console.log("Loading optional service");

216

return OptionalService;

217

})

218

});

219

```

220

221

### Circular Dependency Resolution

222

223

Advanced patterns for resolving complex circular dependencies.

224

225

**Usage Examples:**

226

227

```typescript

228

// Complex circular dependency scenario

229

interface IUserService {

230

getUser(id: string): User;

231

getUserWithOrders(id: string): UserWithOrders;

232

}

233

234

interface IOrderService {

235

getOrder(id: string): Order;

236

getOrdersForUser(userId: string): Order[];

237

}

238

239

interface INotificationService {

240

notifyUser(userId: string, message: string): void;

241

notifyOrderUpdate(orderId: string): void;

242

}

243

244

@injectable()

245

class UserService implements IUserService {

246

constructor(

247

@inject("IOrderService") private orderService: IOrderService,

248

@inject("INotificationService") private notificationService: INotificationService

249

) {}

250

251

getUser(id: string): User {

252

return { id, name: `User ${id}` };

253

}

254

255

getUserWithOrders(id: string): UserWithOrders {

256

const user = this.getUser(id);

257

const orders = this.orderService.getOrdersForUser(id);

258

return { ...user, orders };

259

}

260

}

261

262

@injectable()

263

class OrderService implements IOrderService {

264

constructor(

265

@inject("IUserService") private userService: IUserService,

266

@inject("INotificationService") private notificationService: INotificationService

267

) {}

268

269

getOrder(id: string): Order {

270

return { id, amount: 100 };

271

}

272

273

getOrdersForUser(userId: string): Order[] {

274

// Validate user exists (circular call)

275

const user = this.userService.getUser(userId);

276

return [{ id: "1", amount: 100 }];

277

}

278

}

279

280

@injectable()

281

class NotificationService implements INotificationService {

282

constructor(

283

@inject("IUserService") private userService: IUserService,

284

@inject("IOrderService") private orderService: IOrderService

285

) {}

286

287

notifyUser(userId: string, message: string): void {

288

const user = this.userService.getUser(userId);

289

console.log(`Notifying ${user.name}: ${message}`);

290

}

291

292

notifyOrderUpdate(orderId: string): void {

293

const order = this.orderService.getOrder(orderId);

294

console.log(`Order ${order.id} updated`);

295

}

296

}

297

298

// Register services with delays to break circular dependencies

299

container.register("IUserService", UserService);

300

container.register("IOrderService", {

301

useClass: delay(() => OrderService)

302

});

303

container.register("INotificationService", {

304

useClass: delay(() => NotificationService)

305

});

306

307

// All services can now be resolved successfully

308

const userService = container.resolve<IUserService>("IUserService");

309

const userWithOrders = userService.getUserWithOrders("123");

310

```

311

312

## Types

313

314

```typescript { .api }

315

// Delayed constructor class

316

class DelayedConstructor<T> {

317

createProxy(createObject: (ctor: constructor<T>) => T): T;

318

}

319

320

// Delay function signature

321

function delay<T>(wrappedConstructor: () => constructor<T>): DelayedConstructor<T>;

322

323

// Constructor type

324

type constructor<T> = {new (...args: any[]): T};

325

326

// Wrapped constructor function type

327

type WrappedConstructor<T> = () => constructor<T>;

328

329

// Proxy creation function type

330

type ProxyCreationFunction<T> = (ctor: constructor<T>) => T;

331

```