| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990 |
- import { isFunction } from '@vue/shared'
- import { currentInstance } from './component'
- import { currentRenderingInstance } from './componentRenderContext'
- import { currentApp } from './apiCreateApp'
- import { warn } from './warning'
- export interface InjectionKey<T> extends Symbol {}
- export function provide<T, K = InjectionKey<T> | string | number>(
- key: K,
- value: K extends InjectionKey<infer V> ? V : T,
- ) {
- if (!currentInstance) {
- if (__DEV__) {
- warn(`provide() can only be used inside setup().`)
- }
- } else {
- let provides = currentInstance.provides
- // by default an instance inherits its parent's provides object
- // but when it needs to provide values of its own, it creates its
- // own provides object using parent provides object as prototype.
- // this way in `inject` we can simply look up injections from direct
- // parent and let the prototype chain do the work.
- const parentProvides =
- currentInstance.parent && currentInstance.parent.provides
- if (parentProvides === provides) {
- provides = currentInstance.provides = Object.create(parentProvides)
- }
- // TS doesn't allow symbol as index type
- provides[key as string] = value
- }
- }
- export function inject<T>(key: InjectionKey<T> | string): T | undefined
- export function inject<T>(
- key: InjectionKey<T> | string,
- defaultValue: T,
- treatDefaultAsFactory?: false,
- ): T
- export function inject<T>(
- key: InjectionKey<T> | string,
- defaultValue: T | (() => T),
- treatDefaultAsFactory: true,
- ): T
- export function inject(
- key: InjectionKey<any> | string,
- defaultValue?: unknown,
- treatDefaultAsFactory = false,
- ) {
- // fallback to `currentRenderingInstance` so that this can be called in
- // a functional component
- const instance = currentInstance || currentRenderingInstance
- // also support looking up from app-level provides w/ `app.runWithContext()`
- if (instance || currentApp) {
- // #2400
- // to support `app.use` plugins,
- // fallback to appContext's `provides` if the instance is at root
- // #11488, in a nested createApp, prioritize using the provides from currentApp
- const provides = currentApp
- ? currentApp._context.provides
- : instance
- ? instance.parent == null
- ? instance.vnode.appContext && instance.vnode.appContext.provides
- : instance.parent.provides
- : undefined
- if (provides && (key as string | symbol) in provides) {
- // TS doesn't allow symbol as index type
- return provides[key as string]
- } else if (arguments.length > 1) {
- return treatDefaultAsFactory && isFunction(defaultValue)
- ? defaultValue.call(instance && instance.proxy)
- : defaultValue
- } else if (__DEV__) {
- warn(`injection "${String(key)}" not found.`)
- }
- } else if (__DEV__) {
- warn(`inject() can only be used inside setup() or functional components.`)
- }
- }
- /**
- * Returns true if `inject()` can be used without warning about being called in the wrong place (e.g. outside of
- * setup()). This is used by libraries that want to use `inject()` internally without triggering a warning to the end
- * user. One example is `useRoute()` in `vue-router`.
- */
- export function hasInjectionContext(): boolean {
- return !!(currentInstance || currentRenderingInstance || currentApp)
- }
|