apiInject.ts 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import { isFunction } from '@vue/shared'
  2. import { currentInstance } from './component'
  3. import { currentRenderingInstance } from './componentRenderContext'
  4. import { warn } from './warning'
  5. export interface InjectionKey<T> extends Symbol {}
  6. export function provide<T>(key: InjectionKey<T> | string | number, value: T) {
  7. if (!currentInstance) {
  8. if (__DEV__) {
  9. warn(`provide() can only be used inside setup().`)
  10. }
  11. } else {
  12. let provides = currentInstance.provides
  13. // by default an instance inherits its parent's provides object
  14. // but when it needs to provide values of its own, it creates its
  15. // own provides object using parent provides object as prototype.
  16. // this way in `inject` we can simply look up injections from direct
  17. // parent and let the prototype chain do the work.
  18. const parentProvides =
  19. currentInstance.parent && currentInstance.parent.provides
  20. if (parentProvides === provides) {
  21. provides = currentInstance.provides = Object.create(parentProvides)
  22. }
  23. // TS doesn't allow symbol as index type
  24. provides[key as string] = value
  25. }
  26. }
  27. export function inject<T>(key: InjectionKey<T> | string): T | undefined
  28. export function inject<T>(
  29. key: InjectionKey<T> | string,
  30. defaultValue: T,
  31. treatDefaultAsFactory?: false
  32. ): T
  33. export function inject<T>(
  34. key: InjectionKey<T> | string,
  35. defaultValue: T | (() => T),
  36. treatDefaultAsFactory: true
  37. ): T
  38. export function inject(
  39. key: InjectionKey<any> | string,
  40. defaultValue?: unknown,
  41. treatDefaultAsFactory = false
  42. ) {
  43. // fallback to `currentRenderingInstance` so that this can be called in
  44. // a functional component
  45. const instance = currentInstance || currentRenderingInstance
  46. if (instance) {
  47. // #2400
  48. // to support `app.use` plugins,
  49. // fallback to appContext's `provides` if the instance is at root
  50. const provides =
  51. instance.parent == null
  52. ? instance.vnode.appContext && instance.vnode.appContext.provides
  53. : instance.parent.provides
  54. if (provides && (key as string | symbol) in provides) {
  55. // TS doesn't allow symbol as index type
  56. return provides[key as string]
  57. } else if (arguments.length > 1) {
  58. return treatDefaultAsFactory && isFunction(defaultValue)
  59. ? defaultValue.call(instance.proxy)
  60. : defaultValue
  61. } else if (__DEV__) {
  62. warn(`injection "${String(key)}" not found.`)
  63. }
  64. } else if (__DEV__) {
  65. warn(`inject() can only be used inside setup() or functional components.`)
  66. }
  67. }