diff --git a/packages/runtime-core/__tests__/componentProxy.spec.ts b/packages/runtime-core/__tests__/componentProxy.spec.ts index 8ea2ace2079..ee8f2bc75d5 100644 --- a/packages/runtime-core/__tests__/componentProxy.spec.ts +++ b/packages/runtime-core/__tests__/componentProxy.spec.ts @@ -175,4 +175,18 @@ describe('component: proxy', () => { instanceProxy.baz = 1 expect('baz' in instanceProxy).toBe(true) }) + + // #864 + test('should not warn declared but absent props', () => { + const Comp = { + props: ['test'], + render(this: any) { + return this.test + } + } + render(h(Comp), nodeOps.createElement('div')) + expect( + `was accessed during render but is not defined` + ).not.toHaveBeenWarned() + }) }) diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts index 0e55d022686..f9de525c87d 100644 --- a/packages/runtime-core/src/componentProps.ts +++ b/packages/runtime-core/src/componentProps.ts @@ -12,7 +12,8 @@ import { toRawType, PatchFlags, makeMap, - isReservedProp + isReservedProp, + EMPTY_ARR } from '@vue/shared' import { warn } from './warning' import { Data, ComponentInternalInstance } from './component' @@ -216,11 +217,11 @@ function validatePropName(key: string) { return false } -function normalizePropsOptions( +export function normalizePropsOptions( raw: ComponentPropsOptions | void ): NormalizedPropsOptions { if (!raw) { - return [] as any + return EMPTY_ARR as any } if (normalizationMap.has(raw)) { return normalizationMap.get(raw)! diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index eb496f658d2..442f3f32af0 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -15,6 +15,7 @@ import { currentRenderingInstance, markAttrsAccessed } from './componentRenderUtils' +import { normalizePropsOptions } from './componentProps' // public properties exposed on the proxy, which is used as the render context // in templates (as `this` in the render option) @@ -75,15 +76,7 @@ const enum AccessTypes { export const PublicInstanceProxyHandlers: ProxyHandler = { get(target: ComponentInternalInstance, key: string) { - const { - renderContext, - data, - props, - propsProxy, - accessCache, - type, - sink - } = target + const { renderContext, data, propsProxy, accessCache, type, sink } = target // data / props / renderContext // This getter gets called for every property access on the render context @@ -110,9 +103,9 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { accessCache![key] = AccessTypes.CONTEXT return renderContext[key] } else if (type.props) { - // only cache other properties when instance has declared (this stable) + // only cache other properties when instance has declared (thus stable) // props - if (hasOwn(props, key)) { + if (hasOwn(normalizePropsOptions(type.props)[0], key)) { accessCache![key] = AccessTypes.PROPS // return the value from propsProxy for ref unwrapping and readonly return propsProxy![key]