组合式函数中应封装 inject 逻辑为 useInject,支持泛型、默认值、必填校验及环境差异化处理;配合 Symbol 键保障类型安全;按需扩展响应式访问器或插件级校验。

在组合式函数中封装依赖注入的获取与校验逻辑,核心是把 inject 调用、类型检查、默认值处理、缺失提示等统一抽象,避免每个组件重复写 const xxx = inject('key') 和防御性判断。
定义带类型和校验的 inject 工具函数
创建一个可复用的 useInject 组合式函数,接收 key、默认值、是否必填等参数:
- 用泛型约束返回值类型,配合 TypeScript 提升安全性
- 当未提供依赖且无默认值时,抛出明确错误(开发环境)或返回 undefined(生产环境)
- 支持传入工厂函数生成默认值,避免默认值被提前执行
示例代码:
import { inject, getCurrentInstance } from 'vue'
export function useInject<T>(
key: string | symbol,
defaultValue?: T | (() => T),
options: { required?: boolean; warnOnMissing?: boolean } = {}
) {
const instance = getCurrentInstance()
const isProd = import.meta.env.PROD
// 先尝试 inject
let value = inject<T>(key, undefined as any)
// 若未注入且有默认值,按需解析
if (value === undefined && defaultValue !== undefined) {
value = typeof defaultValue === 'function' ? (defaultValue as Function)() : defaultValue
}
// 若仍为 undefined,按 required 策略处理
if (value === undefined) {
if (options.required) {
const msg = `Missing required injection '${String(key)}'`
if (isProd) {
console.warn(msg)
} else {
throw new Error(msg)
}
}
if (options.warnOnMissing && !isProd) {
console.warn(`Injection '${String(key)}' not provided. Using fallback or undefined.`)
}
}
return value
}
配合 Symbol 做类型安全的 key 管理
避免字符串 key 拼写错误或冲突,建议将所有注入名集中定义为 Symbol:
立即学习“前端免费学习笔记(深入)”;
- 在
injections.ts中统一导出 Symbol 键 - provide 侧和 inject 侧都引用同一 Symbol,TypeScript 可自动推导类型
- 组合式函数中直接使用 Symbol,无需字符串字面量
例如:
// injections.ts
export const ThemeSymbol = Symbol('theme')
export const ApiClientSymbol = Symbol('api-client')
// 在 provide 侧(如父组件或插件)
import { ThemeSymbol } from './injections'
provide(ThemeSymbol, reactive({ mode: 'light' }))
// 在组合式函数中
import { ThemeSymbol } from './injections'
const theme = useInject(ThemeSymbol, { mode: 'dark' }, { required: true })
封装带响应式联动的依赖访问器
某些场景下,不仅需要读取注入值,还需触发更新或监听变化(比如主题切换后刷新 UI),可进一步封装:
- 返回一个包含
value和update方法的对象(若提供者暴露了修改函数) - 或返回一个计算属性
computed(() => ...),自动追踪注入的 ref 或 reactive - 内部做空值 guard,防止因注入未就绪导致的运行时错误
示例:
import { inject, computed, Ref } from 'vue'
import { ThemeSymbol } from './injections'
export function useTheme() {
const theme = inject<Ref<{ mode: string }>>(ThemeSymbol)
if (!theme) {
console.warn('Theme injection not available')
return {
mode: computed(() => 'light'),
setMode: () => {}
}
}
return {
mode: computed(() => theme.value.mode),
setMode: (mode: string) => { theme.value.mode = mode }
}
}
在插件或应用层统一注册并校验
对于全局 app.provide() 注入的依赖(如 i18n、router、auth),可在插件安装时预设校验规则:
- 插件内调用
app.config.globalProperties.$xxx或app.provide同时注册元信息 - 组合式函数首次调用时,检查该 key 是否已在应用级注册(可通过
app._context.provides粗略判断,但不推荐直接访问私有属性) - 更稳妥方式:插件暴露一个
hasInjection(key)工具供组合式函数调用
实际项目中,多数情况只需聚焦前三个方案——类型化 Symbol + 带默认值/报错策略的 useInject + 场景化访问器,就能覆盖 90% 的通用需求。


















