Dùng InjectionKey để provide/inject type-safe, tránh string key collisions:
typescript
// keys.ts — export typed keys
import type { InjectionKey, Ref } from 'vue'
export interface UserContext {
id: number
email: string
role: string
}
export const userContextKey: InjectionKey<UserContext> = Symbol('userContext')
export const themeKey: InjectionKey<Ref<'light' | 'dark'>> = Symbol('theme')
// Parent component
import { provide, ref } from 'vue'
import { userContextKey, themeKey } from './keys'
const theme = ref<'light' | 'dark'>('dark')
provide(themeKey, theme)
provide(userContextKey, { id: 1, email: 'user@test.com', role: 'admin' })
// Child component — fully typed
import { inject } from 'vue'
import { themeKey, userContextKey } from './keys'
const theme = inject(themeKey) // Ref<'light' | 'dark'> | undefined
const user = inject(userContextKey) // UserContext | undefined
// Với default value — loại bỏ undefined
const theme = inject(themeKey, ref('light')) // Ref<'light' | 'dark'>Dùng Symbol làm key thay vì string để tránh naming collision trong large apps hoặc libraries.
Use InjectionKey for type-safe provide/inject with no string collision:
typescript
// keys.ts
import type { InjectionKey, Ref } from 'vue'
export const themeKey: InjectionKey<Ref<'light' | 'dark'>> = Symbol('theme')
export const userKey: InjectionKey<UserContext> = Symbol('user')
// Parent
const theme = ref<'light' | 'dark'>('dark')
provide(themeKey, theme)
// Child — fully typed, no string guessing
const theme = inject(themeKey) // Ref<'light'|'dark'> | undefined
const theme = inject(themeKey, ref('light')) // With default — no undefinedUse Symbol keys instead of strings to avoid naming collisions in large apps or libraries.