Vue3 + TypeScript中provide和inject的用法示例
基础写法(类型安全)
typescript
// parent.component.vue
import { provide, ref } from 'vue'
import type { InjectionKey } from 'vue'// 1. 定义类型化的 InjectionKey
const COUNTER_KEY = Symbol() as InjectionKey<number>
const USER_KEY = Symbol() as InjectionKey<{ name: string }>// 在 setup 中使用
setup() {const counter = ref(0)provide(COUNTER_KEY, counter) // 提供响应式数据const user = { name: 'John' }provide(USER_KEY, user) // 提供静态对象return { counter }
}
typescript
// child.component.vue
import { inject } from 'vue'
import type { InjectionKey } from 'vue'// 复用相同的 key
const COUNTER_KEY = Symbol() as InjectionKey<number>
const USER_KEY = Symbol() as InjectionKey<{ name: string }>setup() {// 2. 安全注入(带默认值)const counter = inject(COUNTER_KEY, ref(0)) // 响应式数据const user = inject(USER_KEY, { name: 'Guest' }) // 静态数据// 3. 强制注入(当确定父级已提供时)const forcedCounter = inject(COUNTER_KEY)!return { counter, user }
}
<script setup> 语法糖写法
vue
<!-- Parent.vue -->
<script setup lang="ts">
import { provide, ref } from 'vue'// 定义 key
const messageKey = Symbol() as InjectionKey<string>const message = ref('Hello from parent')
provide(messageKey, message)
</script>
vue
<!-- Child.vue -->
<script setup lang="ts">
import { inject } from 'vue'const messageKey = Symbol() as InjectionKey<string>// 注入 + 类型声明
const message = inject(messageKey, 'default message')// 处理可能 undefined 的情况
const safeMessage = inject(messageKey) ?? 'fallback value'
</script>
响应式对象注入
typescript
// types.ts
export interface User {id: numbername: string
}export const UserKey = Symbol() as InjectionKey<User>
vue
<!-- Parent.vue -->
<script setup lang="ts">
import { provide, reactive } from 'vue'
import { UserKey } from './types'const user = reactive({id: 1,name: 'Alice'
})provide(UserKey, user)
</script>
vue
<!-- Child.vue -->
<script setup lang="ts">
import { inject } from 'vue'
import { UserKey } from './types'const user = inject(UserKey)// 使用时需要处理可能 undefined 的情况
if (user) {console.log(user.name) // 类型安全
}
</script>
最佳实践提醒:
-
使用
InjectionKey:确保类型安全 -
默认值处理:
inject(key, defaultValue) -
响应式数据:建议使用
ref/reactive保持响应性 -
代码组织:推荐将 keys 集中管理在单独文件中
-
安全判断:当不确定是否已提供时,使用可选链操作符
?.
typescript
// 推荐的文件结构
// src/provides/keys.ts
import type { InjectionKey } from 'vue'export const API_KEY = Symbol() as InjectionKey<AxiosInstance>
export const THEME_KEY = Symbol() as InjectionKey<'light' | 'dark'>