Good Code
The good version provides a narrow, typed context value and keeps mutation at the provider boundary.
Lesson 09
Use provide and inject for narrow context values with typed keys, not as a hidden app-wide dependency channel.
import type { InjectionKey, Ref } from "vue";
import { inject, provide, readonly, ref } from "vue";
type ReviewTheme = "light" | "dark";
const reviewThemeKey: InjectionKey<Readonly<Ref<ReviewTheme>>> =
Symbol("review-theme");
export function provideReviewTheme() {
// Consumers can read the theme but cannot rewrite it directly.
const theme = ref<ReviewTheme>("light");
provide(reviewThemeKey, readonly(theme));
return { theme };
}
export function useReviewTheme() {
const theme = inject(reviewThemeKey);
if (!theme) throw new Error("Review theme provider is missing");
return theme;
}import { inject, provide, reactive } from "vue";
const appContextKey = Symbol("app");
// One mutable object becomes a hidden dependency for many components.
export function provideAppContext() {
const app = reactive({ user: null, reviews: [], settings: {}, theme: "light" });
provide(appContextKey, app);
}
export function useAppContext() {
return inject(appContextKey) as any;
}The good version provides a narrow, typed context value and keeps mutation at the provider boundary.
The bad version injects a broad mutable object. Components can become coupled to unrelated user, review, settings, and theme state.