or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-resolution.mdbuiltin-components.mdcomponents.mdcomposition-helpers.mddependency-injection.mderror-handling.mdhydration.mdindex.mdinternal-render-helpers.mdlifecycle.mdreactivity.mdscheduler-timing.mdssr-context.mdvdom-rendering.mdwatch-effects.md

dependency-injection.mddocs/

0

# Dependency Injection

1

2

Vue's dependency injection system enables sharing data across component hierarchies without prop drilling. It provides type-safe injection with optional default values and context checking.

3

4

## Capabilities

5

6

### Provide & Inject Functions

7

8

Share data from parent components to descendant components at any depth.

9

10

```typescript { .api }

11

/**

12

* Provides a value that can be injected by descendant components

13

* @param key - Injection key (string or symbol)

14

* @param value - Value to provide

15

*/

16

function provide<T>(key: InjectionKey<T> | string, value: T): void;

17

18

/**

19

* Injects a value provided by an ancestor component

20

* @param key - Injection key to look for

21

* @returns Injected value or undefined if not found

22

*/

23

function inject<T>(key: InjectionKey<T> | string): T | undefined;

24

25

/**

26

* Injects a value with a default fallback

27

* @param key - Injection key to look for

28

* @param defaultValue - Default value if injection not found

29

* @returns Injected value or default value

30

*/

31

function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T;

32

33

/**

34

* Injects a value with a factory function for default value

35

* @param key - Injection key to look for

36

* @param defaultValue - Factory function or default value

37

* @param treatAsFactory - Whether to treat defaultValue as factory

38

* @returns Injected value or result of default factory

39

*/

40

function inject<T>(

41

key: InjectionKey<T> | string,

42

defaultValue: T | (() => T),

43

treatAsFactory: boolean

44

): T;

45

46

/**

47

* Checks if injection context is available (component is in setup)

48

* @returns True if injection context is available

49

*/

50

function hasInjectionContext(): boolean;

51

```

52

53

**Usage Examples:**

54

55

```typescript

56

import { defineComponent, ref, provide, inject, InjectionKey } from "@vue/runtime-core";

57

58

// Define typed injection keys

59

const ThemeKey: InjectionKey<{ theme: string; toggleTheme: () => void }> = Symbol('theme');

60

const UserKey: InjectionKey<{ name: string; id: number }> = Symbol('user');

61

62

// Parent component providing values

63

const ParentComponent = defineComponent({

64

setup() {

65

const theme = ref('light');

66

67

const toggleTheme = () => {

68

theme.value = theme.value === 'light' ? 'dark' : 'light';

69

};

70

71

const user = { name: 'Alice', id: 123 };

72

73

// Provide values with typed keys

74

provide(ThemeKey, {

75

theme: theme.value,

76

toggleTheme

77

});

78

79

provide(UserKey, user);

80

81

// Provide with string key

82

provide('api-base-url', 'https://api.example.com');

83

84

return { theme };

85

}

86

});

87

88

// Child component injecting values

89

const ChildComponent = defineComponent({

90

setup() {

91

// Inject with typed key

92

const themeContext = inject(ThemeKey);

93

if (themeContext) {

94

console.log('Current theme:', themeContext.theme);

95

}

96

97

// Inject with default value

98

const user = inject(UserKey, { name: 'Guest', id: 0 });

99

console.log('User:', user.name);

100

101

// Inject string key with default

102

const apiUrl = inject('api-base-url', 'https://fallback.com');

103

104

// Inject with factory default

105

const config = inject('app-config', () => ({ debug: false }), true);

106

107

return {

108

themeContext,

109

user,

110

apiUrl,

111

config

112

};

113

}

114

});

115

```

116

117

### Injection Context Checking

118

119

Verify if injection context is available before attempting injection.

120

121

```typescript { .api }

122

/**

123

* Checks if injection context is available

124

* @returns True if currently in component setup context

125

*/

126

function hasInjectionContext(): boolean;

127

```

128

129

**Usage Examples:**

130

131

```typescript

132

import { inject, hasInjectionContext } from "@vue/runtime-core";

133

134

// Utility function that can be called from setup or outside

135

function useTheme() {

136

if (hasInjectionContext()) {

137

// We're in a component setup context

138

const theme = inject('theme', 'light');

139

return { theme };

140

} else {

141

// We're outside component context, return default

142

console.warn('useTheme called outside component context');

143

return { theme: 'light' };

144

}

145

}

146

147

const MyComponent = defineComponent({

148

setup() {

149

// This will work - we're in setup context

150

const { theme } = useTheme();

151

152

return { theme };

153

}

154

});

155

156

// This will return default - not in component context

157

const { theme } = useTheme();

158

```

159

160

### Advanced Injection Patterns

161

162

Common patterns for complex injection scenarios.

163

164

```typescript

165

import { defineComponent, provide, inject, ref, computed, InjectionKey } from "@vue/runtime-core";

166

167

// Store-like pattern

168

interface Store {

169

state: { count: number };

170

getters: { doubledCount: number };

171

actions: { increment(): void; decrement(): void };

172

}

173

174

const StoreKey: InjectionKey<Store> = Symbol('store');

175

176

const StoreProvider = defineComponent({

177

setup(_, { slots }) {

178

const count = ref(0);

179

180

const store: Store = {

181

state: { count: count.value },

182

getters: {

183

get doubledCount() { return count.value * 2; }

184

},

185

actions: {

186

increment: () => count.value++,

187

decrement: () => count.value--

188

}

189

};

190

191

provide(StoreKey, store);

192

193

return () => slots.default?.();

194

}

195

});

196

197

// Configuration provider pattern

198

interface AppConfig {

199

apiUrl: string;

200

features: { darkMode: boolean; analytics: boolean };

201

version: string;

202

}

203

204

const ConfigKey: InjectionKey<AppConfig> = Symbol('config');

205

206

const ConfigProvider = defineComponent({

207

props: {

208

config: { type: Object as PropType<AppConfig>, required: true }

209

},

210

setup(props, { slots }) {

211

provide(ConfigKey, props.config);

212

return () => slots.default?.();

213

}

214

});

215

216

// Hook pattern for consuming injected values

217

function useStore() {

218

const store = inject(StoreKey);

219

if (!store) {

220

throw new Error('useStore must be used within StoreProvider');

221

}

222

return store;

223

}

224

225

function useConfig() {

226

const config = inject(ConfigKey);

227

if (!config) {

228

throw new Error('useConfig must be used within ConfigProvider');

229

}

230

return config;

231

}

232

```

233

234

## Types

235

236

```typescript { .api }

237

interface InjectionKey<T> extends Symbol {

238

readonly [InjectionKeySymbol]: T;

239

}

240

241

type InjectionConstraint<T> = InjectionKey<T> | string;

242

243

// Helper type for creating injection keys

244

function createInjectionKey<T>(description?: string): InjectionKey<T>;

245

```

246

247

## Best Practices

248

249

### Type Safety

250

251

Use `InjectionKey<T>` for type-safe injection:

252

253

```typescript

254

// Good: Type-safe injection key

255

const UserKey: InjectionKey<User> = Symbol('user');

256

provide(UserKey, user);

257

const injectedUser = inject(UserKey); // Type is User | undefined

258

259

// Avoid: String keys lose type information

260

provide('user', user);

261

const injectedUser = inject('user'); // Type is unknown

262

```

263

264

### Error Handling

265

266

Always handle cases where injection might fail:

267

268

```typescript

269

// Good: Handle missing injection

270

const user = inject(UserKey);

271

if (!user) {

272

throw new Error('User not provided');

273

}

274

275

// Good: Provide default value

276

const user = inject(UserKey, { name: 'Guest', id: 0 });

277

278

// Good: Create helper hook

279

function useUser() {

280

const user = inject(UserKey);

281

if (!user) {

282

throw new Error('useUser must be used within UserProvider');

283

}

284

return user;

285

}

286

```

287

288

### Scoped Providers

289

290

Create provider components for clean injection boundaries:

291

292

```typescript

293

const ThemeProvider = defineComponent({

294

setup(_, { slots }) {

295

const theme = ref('light');

296

provide(ThemeKey, { theme, setTheme: (t: string) => theme.value = t });

297

return () => slots.default?.();

298

}

299

});

300

```