or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-framework.mdcommands.mddependency-injection.mdevents-messaging.mdindex.mdkeybindings.mdmenus.mdpreferences-configuration.mdresources-files.mdwidgets-ui.md

dependency-injection.mddocs/

0

# Dependency Injection System

1

2

Theia Core provides comprehensive dependency injection infrastructure built on InversifyJS, featuring Symbol-based service tokens, contribution patterns, and container management for building extensible applications.

3

4

## Capabilities

5

6

### Injectable Decorator

7

8

Marks a class as injectable for dependency injection container binding.

9

10

```typescript { .api }

11

/**

12

* Marks a class as available for injection

13

* @param target - The class to mark as injectable

14

* @returns The injectable class

15

*/

16

function injectable<T>(target: interfaces.Newable<T>): interfaces.Newable<T>;

17

```

18

19

**Usage Example:**

20

21

```typescript

22

import { injectable } from "@theia/core";

23

24

@injectable()

25

export class MyService {

26

doSomething(): void {

27

console.log("Service method called");

28

}

29

}

30

```

31

32

### Inject Decorator

33

34

Injects dependencies into constructor parameters or properties.

35

36

```typescript { .api }

37

/**

38

* Injects a service into a constructor parameter

39

* @param serviceIdentifier - Symbol or string identifying the service

40

* @returns Parameter decorator

41

*/

42

function inject(serviceIdentifier: interfaces.ServiceIdentifier): ParameterDecorator;

43

```

44

45

**Usage Examples:**

46

47

```typescript

48

import { injectable, inject } from "@theia/core";

49

import { ILogger } from "@theia/core";

50

51

@injectable()

52

export class MyComponent {

53

constructor(

54

@inject(ILogger) private readonly logger: ILogger

55

) {}

56

57

performAction(): void {

58

this.logger.info("Action performed");

59

}

60

}

61

```

62

63

### Contribution Provider

64

65

Collects and provides access to all bound contributions of a specific type.

66

67

```typescript { .api }

68

/**

69

* Provider for collecting contributions of a specific type

70

*/

71

interface ContributionProvider<T> {

72

/**

73

* Get all contributions of type T

74

* @returns Array of all bound contributions

75

*/

76

getContributions(): T[];

77

78

/**

79

* Get all contributions of type T that satisfy the filter

80

* @param filter - Optional filter function

81

* @returns Filtered array of contributions

82

*/

83

getContributions(filter?: (contrib: T) => boolean): T[];

84

}

85

86

/**

87

* Symbol for binding ContributionProvider

88

*/

89

const ContributionProvider: symbol;

90

```

91

92

**Usage Example:**

93

94

```typescript

95

import { injectable, inject } from "@theia/core";

96

import { ContributionProvider, CommandContribution } from "@theia/core";

97

98

@injectable()

99

export class CommandManager {

100

constructor(

101

@inject(ContributionProvider) @named(CommandContribution)

102

private readonly contributions: ContributionProvider<CommandContribution>

103

) {}

104

105

initializeCommands(): void {

106

for (const contribution of this.contributions.getContributions()) {

107

contribution.registerCommands(/* registry */);

108

}

109

}

110

}

111

```

112

113

### Binding Functions

114

115

Utility functions for binding contributions and providers to the container.

116

117

```typescript { .api }

118

/**

119

* Binds a contribution provider to the container

120

* @param bind - Container bind function

121

* @param id - Service identifier for the contribution type

122

*/

123

function bindContributionProvider(

124

bind: interfaces.Bind,

125

id: interfaces.ServiceIdentifier

126

): void;

127

128

/**

129

* Binds a single contribution to the container

130

* @param bind - Container bind function

131

* @param id - Service identifier for the contribution type

132

* @param contribution - The contribution class to bind

133

*/

134

function bindContribution<T>(

135

bind: interfaces.Bind,

136

id: interfaces.ServiceIdentifier<T>,

137

contribution: interfaces.Newable<T>

138

): void;

139

```

140

141

**Usage Example:**

142

143

```typescript

144

import { ContainerModule } from "inversify";

145

import { bindContributionProvider, CommandContribution } from "@theia/core";

146

147

export default new ContainerModule(bind => {

148

// Bind the contribution provider

149

bindContributionProvider(bind, CommandContribution);

150

151

// Bind individual contributions

152

bind(CommandContribution).to(MyCommandContribution).inSingletonScope();

153

bind(CommandContribution).to(AnotherCommandContribution).inSingletonScope();

154

});

155

```

156

157

### Named Binding

158

159

Decorator for named service bindings when multiple implementations exist.

160

161

```typescript { .api }

162

/**

163

* Named binding decorator for distinguishing between multiple implementations

164

* @param name - The name to identify this binding

165

* @returns Parameter decorator

166

*/

167

function named(name: string | number | symbol): ParameterDecorator;

168

```

169

170

**Usage Example:**

171

172

```typescript

173

import { injectable, inject, named } from "@theia/core";

174

175

interface StorageService {

176

get(key: string): string | undefined;

177

set(key: string, value: string): void;

178

}

179

180

@injectable()

181

export class ConfigurationManager {

182

constructor(

183

@inject('StorageService') @named('user')

184

private readonly userStorage: StorageService,

185

186

@inject('StorageService') @named('workspace')

187

private readonly workspaceStorage: StorageService

188

) {}

189

}

190

```

191

192

### Container Management

193

194

Utilities for working with InversifyJS containers in Theia applications.

195

196

```typescript { .api }

197

/**

198

* Application container type

199

*/

200

type ApplicationContainer = interfaces.Container;

201

202

/**

203

* Bindable type for flexible binding

204

*/

205

type Bindable = interfaces.Bind | interfaces.Container;

206

```

207

208

**Usage Example:**

209

210

```typescript

211

import { Container, ContainerModule } from "inversify";

212

import { bindContributionProvider } from "@theia/core";

213

214

// Create application container

215

const container = new Container();

216

217

// Load extension modules

218

const extensionModule = new ContainerModule(bind => {

219

bindContributionProvider(bind, CommandContribution);

220

bind(MyService).toSelf().inSingletonScope();

221

});

222

223

container.load(extensionModule);

224

225

// Get services

226

const myService = container.get(MyService);

227

```

228

229

### Optional Injection

230

231

Handle optional dependencies that may not be bound.

232

233

```typescript { .api }

234

/**

235

* Optional injection decorator

236

* @param serviceIdentifier - Service identifier

237

* @returns Parameter decorator that allows undefined injection

238

*/

239

function optional(): ParameterDecorator;

240

```

241

242

**Usage Example:**

243

244

```typescript

245

import { injectable, inject, optional } from "@theia/core";

246

247

@injectable()

248

export class OptionalServiceConsumer {

249

constructor(

250

@inject('RequiredService') private readonly required: RequiredService,

251

@inject('OptionalService') @optional()

252

private readonly optional?: OptionalService

253

) {}

254

255

performAction(): void {

256

// Always available

257

this.required.doSomething();

258

259

// Check if optional service is available

260

if (this.optional) {

261

this.optional.doOptionalThing();

262

}

263

}

264

}

265

```

266

267

## Service Binding Patterns

268

269

### Singleton Scope

270

271

Most Theia services should be bound in singleton scope:

272

273

```typescript

274

bind(MyService).toSelf().inSingletonScope();

275

```

276

277

### Contribution Pattern

278

279

Extensions contribute implementations through the contribution pattern:

280

281

```typescript

282

// 1. Define contribution interface

283

interface MyContribution {

284

configure(): void;

285

}

286

287

// 2. Bind contribution provider

288

bindContributionProvider(bind, MyContribution);

289

290

// 3. Extensions bind their implementations

291

bind(MyContribution).to(MyImplementation).inSingletonScope();

292

293

// 4. Core service consumes all contributions

294

@injectable()

295

export class MyManager {

296

constructor(

297

@inject(ContributionProvider) @named(MyContribution)

298

private readonly contributions: ContributionProvider<MyContribution>

299

) {}

300

301

initialize(): void {

302

for (const contrib of this.contributions.getContributions()) {

303

contrib.configure();

304

}

305

}

306

}

307

```

308

309

### Service Factories

310

311

Create services with runtime parameters:

312

313

```typescript

314

bind('ServiceFactory').toFactory(context =>

315

(config: ServiceConfig) => {

316

const service = context.container.get(ServiceImpl);

317

service.configure(config);

318

return service;

319

}

320

);

321

```

322

323

## Types

324

325

```typescript { .api }

326

// InversifyJS types re-exported from Theia

327

type ServiceIdentifier<T = any> = interfaces.ServiceIdentifier<T>;

328

type Bind = interfaces.Bind;

329

type Container = interfaces.Container;

330

type ContainerModule = interfaces.ContainerModule;

331

332

interface Newable<T> {

333

new (...args: any[]): T;

334

}

335

336

interface Abstract<T> {

337

prototype: T;

338

}

339

```