feat(types): feat(types): add ComponentCustomProperties interface (#982)

This commit is contained in:
Evan You 2020-04-17 09:12:50 -04:00
parent 4cf5e07608
commit be21cfb1db
5 changed files with 59 additions and 7 deletions

View File

@ -20,7 +20,6 @@ import {
import { import {
currentInstance, currentInstance,
ComponentInternalInstance, ComponentInternalInstance,
Data,
isInSSRComponentSetup, isInSSRComponentSetup,
recordInstanceBoundEffect recordInstanceBoundEffect
} from './component' } from './component'
@ -276,9 +275,11 @@ export function instanceWatch(
cb: Function, cb: Function,
options?: WatchOptions options?: WatchOptions
): StopHandle { ): StopHandle {
const ctx = this.proxy as Data const publicThis = this.proxy as any
const getter = isString(source) ? () => ctx[source] : source.bind(ctx) const getter = isString(source)
const stop = watch(getter, cb.bind(ctx), options) ? () => publicThis[source]
: source.bind(publicThis)
const stop = watch(getter, cb.bind(publicThis), options)
onBeforeUnmount(stop, this) onBeforeUnmount(stop, this)
return stop return stop
} }

View File

@ -528,7 +528,7 @@ function createWatcher(
publicThis: ComponentPublicInstance, publicThis: ComponentPublicInstance,
key: string key: string
) { ) {
const getter = () => (publicThis as Data)[key] const getter = () => (publicThis as any)[key]
if (isString(raw)) { if (isString(raw)) {
const handler = ctx[raw] const handler = ctx[raw]
if (isFunction(handler)) { if (isFunction(handler)) {

View File

@ -24,6 +24,33 @@ import {
} from './componentRenderUtils' } from './componentRenderUtils'
import { warn } from './warning' 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 // public properties exposed on the proxy, which is used as the render context
// in templates (as `this` in the render option) // in templates (as `this` in the render option)
export type ComponentPublicInstance< export type ComponentPublicInstance<
@ -53,7 +80,8 @@ export type ComponentPublicInstance<
UnwrapRef<B> & UnwrapRef<B> &
D & D &
ExtractComputedReturns<C> & ExtractComputedReturns<C> &
M M &
ComponentCustomProperties
const publicPropertiesMap: Record< const publicPropertiesMap: Record<
string, string,

View File

@ -192,7 +192,10 @@ export {
ComponentOptionsWithObjectProps as ComponentOptionsWithProps, ComponentOptionsWithObjectProps as ComponentOptionsWithProps,
ComponentOptionsWithArrayProps ComponentOptionsWithArrayProps
} from './componentOptions' } from './componentOptions'
export { ComponentPublicInstance } from './componentProxy' export {
ComponentPublicInstance,
ComponentCustomProperties
} from './componentProxy'
export { export {
Renderer, Renderer,
RendererNode, RendererNode,

View File

@ -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'))
}
}
})