]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(types): feat(types): add `ComponentCustomProperties` interface (#982)
authorEvan You <yyx990803@gmail.com>
Fri, 17 Apr 2020 13:12:50 +0000 (09:12 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 17 Apr 2020 13:12:50 +0000 (09:12 -0400)
packages/runtime-core/src/apiWatch.ts
packages/runtime-core/src/componentOptions.ts
packages/runtime-core/src/componentProxy.ts
packages/runtime-core/src/index.ts
test-dts/componentCustomProperties.test-d.ts [new file with mode: 0644]

index 967c77f8f977bc920eb034ad8df5ab0955da1796..ff3e7c6257ea4105c774437925fe4c5b9a55652f 100644 (file)
@@ -20,7 +20,6 @@ import {
 import {
   currentInstance,
   ComponentInternalInstance,
-  Data,
   isInSSRComponentSetup,
   recordInstanceBoundEffect
 } from './component'
@@ -276,9 +275,11 @@ export function instanceWatch(
   cb: Function,
   options?: WatchOptions
 ): StopHandle {
-  const ctx = this.proxy as Data
-  const getter = isString(source) ? () => ctx[source] : source.bind(ctx)
-  const stop = watch(getter, cb.bind(ctx), options)
+  const publicThis = this.proxy as any
+  const getter = isString(source)
+    ? () => publicThis[source]
+    : source.bind(publicThis)
+  const stop = watch(getter, cb.bind(publicThis), options)
   onBeforeUnmount(stop, this)
   return stop
 }
index e8fbfad4ab3bf93f20444ee018af41fc39db73bc..39087e8c311aed36a3f5a4dd10fc4dd693cce10c 100644 (file)
@@ -528,7 +528,7 @@ function createWatcher(
   publicThis: ComponentPublicInstance,
   key: string
 ) {
-  const getter = () => (publicThis as Data)[key]
+  const getter = () => (publicThis as any)[key]
   if (isString(raw)) {
     const handler = ctx[raw]
     if (isFunction(handler)) {
index 03044d07f4e807b249b2b8a44e704d9e5509ce7f..183207e90ab5b51fae5084eb341fefb4287eb45f 100644 (file)
@@ -24,6 +24,33 @@ import {
 } from './componentRenderUtils'
 import { warn } from './warning'
 
+/**
+ * Custom properties added to component instances in any way and can be accessed through `this`
+ *
+ * @example
+ * Here is an example of adding a property `$router` to every component instance:
+ * ```ts
+ * import { createApp } from 'vue'
+ * import { Router, createRouter } from 'vue-router'
+ *
+ * declare module '@vue/runtime-core' {
+ *   interface ComponentCustomProperties {
+ *     $router: Router
+ *   }
+ * }
+ *
+ * // effectively adding the router to every component instance
+ * const app = createApp({})
+ * const router = createRouter()
+ * app.config.globalProperties.$router = router
+ *
+ * const vm = app.mount('#app')
+ * // we can access the router from the instance
+ * vm.$router.push('/')
+ * ```
+ */
+export interface ComponentCustomProperties {}
+
 // public properties exposed on the proxy, which is used as the render context
 // in templates (as `this` in the render option)
 export type ComponentPublicInstance<
@@ -53,7 +80,8 @@ export type ComponentPublicInstance<
   UnwrapRef<B> &
   D &
   ExtractComputedReturns<C> &
-  M
+  M &
+  ComponentCustomProperties
 
 const publicPropertiesMap: Record<
   string,
index 934ae9731cc53404660cb4d2de8579a866e52df3..f4273cc37c0581f949458cec29c16af8252b9409 100644 (file)
@@ -192,7 +192,10 @@ export {
   ComponentOptionsWithObjectProps as ComponentOptionsWithProps,
   ComponentOptionsWithArrayProps
 } from './componentOptions'
-export { ComponentPublicInstance } from './componentProxy'
+export {
+  ComponentPublicInstance,
+  ComponentCustomProperties
+} from './componentProxy'
 export {
   Renderer,
   RendererNode,
diff --git a/test-dts/componentCustomProperties.test-d.ts b/test-dts/componentCustomProperties.test-d.ts
new file mode 100644 (file)
index 0000000..60267c6
--- /dev/null
@@ -0,0 +1,20 @@
+import { expectError } from 'tsd'
+import { defineComponent } from './index'
+
+declare module '@vue/runtime-core' {
+  interface ComponentCustomProperties {
+    state: 'stopped' | 'running'
+  }
+}
+
+export const Custom = defineComponent({
+  data: () => ({ counter: 0 }),
+  methods: {
+    aMethod() {
+      expectError(this.notExisting)
+      this.counter++
+      this.state = 'running'
+      expectError((this.state = 'not valid'))
+    }
+  }
+})