Vue.js 3 runtime core library providing foundational APIs for building custom renderers and managing reactive component systems
—
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.
Share data from parent components to descendant components at any depth.
/**
* Provides a value that can be injected by descendant components
* @param key - Injection key (string or symbol)
* @param value - Value to provide
*/
function provide<T>(key: InjectionKey<T> | string, value: T): void;
/**
* Injects a value provided by an ancestor component
* @param key - Injection key to look for
* @returns Injected value or undefined if not found
*/
function inject<T>(key: InjectionKey<T> | string): T | undefined;
/**
* Injects a value with a default fallback
* @param key - Injection key to look for
* @param defaultValue - Default value if injection not found
* @returns Injected value or default value
*/
function inject<T>(key: InjectionKey<T> | string, defaultValue: T): T;
/**
* Injects a value with a factory function for default value
* @param key - Injection key to look for
* @param defaultValue - Factory function or default value
* @param treatAsFactory - Whether to treat defaultValue as factory
* @returns Injected value or result of default factory
*/
function inject<T>(
key: InjectionKey<T> | string,
defaultValue: T | (() => T),
treatAsFactory: boolean
): T;
/**
* Checks if injection context is available (component is in setup)
* @returns True if injection context is available
*/
function hasInjectionContext(): boolean;Usage Examples:
import { defineComponent, ref, provide, inject, InjectionKey } from "@vue/runtime-core";
// Define typed injection keys
const ThemeKey: InjectionKey<{ theme: string; toggleTheme: () => void }> = Symbol('theme');
const UserKey: InjectionKey<{ name: string; id: number }> = Symbol('user');
// Parent component providing values
const ParentComponent = defineComponent({
setup() {
const theme = ref('light');
const toggleTheme = () => {
theme.value = theme.value === 'light' ? 'dark' : 'light';
};
const user = { name: 'Alice', id: 123 };
// Provide values with typed keys
provide(ThemeKey, {
theme: theme.value,
toggleTheme
});
provide(UserKey, user);
// Provide with string key
provide('api-base-url', 'https://api.example.com');
return { theme };
}
});
// Child component injecting values
const ChildComponent = defineComponent({
setup() {
// Inject with typed key
const themeContext = inject(ThemeKey);
if (themeContext) {
console.log('Current theme:', themeContext.theme);
}
// Inject with default value
const user = inject(UserKey, { name: 'Guest', id: 0 });
console.log('User:', user.name);
// Inject string key with default
const apiUrl = inject('api-base-url', 'https://fallback.com');
// Inject with factory default
const config = inject('app-config', () => ({ debug: false }), true);
return {
themeContext,
user,
apiUrl,
config
};
}
});Verify if injection context is available before attempting injection.
/**
* Checks if injection context is available
* @returns True if currently in component setup context
*/
function hasInjectionContext(): boolean;Usage Examples:
import { inject, hasInjectionContext } from "@vue/runtime-core";
// Utility function that can be called from setup or outside
function useTheme() {
if (hasInjectionContext()) {
// We're in a component setup context
const theme = inject('theme', 'light');
return { theme };
} else {
// We're outside component context, return default
console.warn('useTheme called outside component context');
return { theme: 'light' };
}
}
const MyComponent = defineComponent({
setup() {
// This will work - we're in setup context
const { theme } = useTheme();
return { theme };
}
});
// This will return default - not in component context
const { theme } = useTheme();Common patterns for complex injection scenarios.
import { defineComponent, provide, inject, ref, computed, InjectionKey } from "@vue/runtime-core";
// Store-like pattern
interface Store {
state: { count: number };
getters: { doubledCount: number };
actions: { increment(): void; decrement(): void };
}
const StoreKey: InjectionKey<Store> = Symbol('store');
const StoreProvider = defineComponent({
setup(_, { slots }) {
const count = ref(0);
const store: Store = {
state: { count: count.value },
getters: {
get doubledCount() { return count.value * 2; }
},
actions: {
increment: () => count.value++,
decrement: () => count.value--
}
};
provide(StoreKey, store);
return () => slots.default?.();
}
});
// Configuration provider pattern
interface AppConfig {
apiUrl: string;
features: { darkMode: boolean; analytics: boolean };
version: string;
}
const ConfigKey: InjectionKey<AppConfig> = Symbol('config');
const ConfigProvider = defineComponent({
props: {
config: { type: Object as PropType<AppConfig>, required: true }
},
setup(props, { slots }) {
provide(ConfigKey, props.config);
return () => slots.default?.();
}
});
// Hook pattern for consuming injected values
function useStore() {
const store = inject(StoreKey);
if (!store) {
throw new Error('useStore must be used within StoreProvider');
}
return store;
}
function useConfig() {
const config = inject(ConfigKey);
if (!config) {
throw new Error('useConfig must be used within ConfigProvider');
}
return config;
}interface InjectionKey<T> extends Symbol {
readonly [InjectionKeySymbol]: T;
}
type InjectionConstraint<T> = InjectionKey<T> | string;
// Helper type for creating injection keys
function createInjectionKey<T>(description?: string): InjectionKey<T>;Use InjectionKey<T> for type-safe injection:
// Good: Type-safe injection key
const UserKey: InjectionKey<User> = Symbol('user');
provide(UserKey, user);
const injectedUser = inject(UserKey); // Type is User | undefined
// Avoid: String keys lose type information
provide('user', user);
const injectedUser = inject('user'); // Type is unknownAlways handle cases where injection might fail:
// Good: Handle missing injection
const user = inject(UserKey);
if (!user) {
throw new Error('User not provided');
}
// Good: Provide default value
const user = inject(UserKey, { name: 'Guest', id: 0 });
// Good: Create helper hook
function useUser() {
const user = inject(UserKey);
if (!user) {
throw new Error('useUser must be used within UserProvider');
}
return user;
}Create provider components for clean injection boundaries:
const ThemeProvider = defineComponent({
setup(_, { slots }) {
const theme = ref('light');
provide(ThemeKey, { theme, setTheme: (t: string) => theme.value = t });
return () => slots.default?.();
}
});Install with Tessl CLI
npx tessl i tessl/npm-vue--runtime-core