diff --git a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/definePropsDestructure.spec.ts.snap b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/definePropsDestructure.spec.ts.snap index 1044b0e167c..2957a42292a 100644 --- a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/definePropsDestructure.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/definePropsDestructure.spec.ts.snap @@ -101,13 +101,14 @@ exports[`sfc reactive props destructure > default values w/ runtime declaration "import { mergeDefaults as _mergeDefaults } from 'vue' export default { - props: /*@__PURE__*/_mergeDefaults(['foo', 'foo:bar'], { + props: /*@__PURE__*/_mergeDefaults(['foo', 'foo:bar', 'baz'], { foo: 1, - "foo:bar": 'foo-bar' + "foo:bar": 'foo-bar', + baz: (props) => (props["foo"]) }), setup(__props) { - + __props.foo return () => {} } @@ -142,11 +143,12 @@ export default /*@__PURE__*/_defineComponent({ props: { foo: { type: Number, required: false, default: 1 }, bar: { type: Object, required: false, default: () => ({}) }, - func: { type: Function, required: false, default: () => {} } + func: { type: Function, required: false, default: () => {} }, + baz: { type: Object, required: false, default: (props) => (props["bar"]) } }, setup(__props: any) { - + __props.bar return () => {} } diff --git a/packages/compiler-sfc/__tests__/compileScript/definePropsDestructure.spec.ts b/packages/compiler-sfc/__tests__/compileScript/definePropsDestructure.spec.ts index 50602eb59bc..de242e91452 100644 --- a/packages/compiler-sfc/__tests__/compileScript/definePropsDestructure.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript/definePropsDestructure.spec.ts @@ -106,25 +106,28 @@ describe('sfc reactive props destructure', () => { })`) assertCode(content) }) + test('default values w/ runtime declaration & key is string', () => { const { content, bindings } = compile(` `) expect(bindings).toStrictEqual({ __propsAliases: { fooBar: 'foo:bar', }, + baz: BindingTypes.PROPS, foo: BindingTypes.PROPS, 'foo:bar': BindingTypes.PROPS, fooBar: BindingTypes.PROPS_ALIASED, }) expect(content).toMatch(` - props: /*@__PURE__*/_mergeDefaults(['foo', 'foo:bar'], { + props: /*@__PURE__*/_mergeDefaults(['foo', 'foo:bar', 'baz'], { foo: 1, - "foo:bar": 'foo-bar' + "foo:bar": 'foo-bar', + baz: (props) => (props["foo"]) }),`) assertCode(content) }) @@ -132,7 +135,7 @@ describe('sfc reactive props destructure', () => { test('default values w/ type declaration', () => { const { content } = compile(` `) // literals can be used as-is, non-literals are always returned from a @@ -140,7 +143,8 @@ describe('sfc reactive props destructure', () => { expect(content).toMatch(`props: { foo: { type: Number, required: false, default: 1 }, bar: { type: Object, required: false, default: () => ({}) }, - func: { type: Function, required: false, default: () => {} } + func: { type: Function, required: false, default: () => {} }, + baz: { type: Object, required: false, default: (props) => (props["bar"]) } }`) assertCode(content) }) diff --git a/packages/compiler-sfc/src/script/defineProps.ts b/packages/compiler-sfc/src/script/defineProps.ts index 9a4880a1a54..a89c89769b7 100644 --- a/packages/compiler-sfc/src/script/defineProps.ts +++ b/packages/compiler-sfc/src/script/defineProps.ts @@ -349,13 +349,16 @@ function genDestructuredDefaultValue( } } + const isDestructuredBinding = ctx.propsDestructuredBindings[value] + // If the default value is a function or is an identifier referencing // external value, skip factory wrap. This is needed when using // destructure w/ runtime declaration since we cannot safely infer // whether the expected runtime prop type is `Function`. const needSkipFactory = !inferredType && - (isFunctionType(unwrapped) || unwrapped.type === 'Identifier') + (isFunctionType(unwrapped) || + (unwrapped.type === 'Identifier' && !isDestructuredBinding)) const needFactoryWrap = !needSkipFactory && @@ -363,13 +366,17 @@ function genDestructuredDefaultValue( !inferredType?.includes('Function') return { - valueString: needFactoryWrap ? `() => (${value})` : value, + valueString: needFactoryWrap + ? isDestructuredBinding + ? `(props) => (props["${value}"])` + : `() => (${value})` + : value, needSkipFactory, } } } -// non-comprehensive, best-effort type infernece for a runtime value +// non-comprehensive, best-effort type inference for a runtime value // this is used to catch default value / type declaration mismatches // when using props destructure. function inferValueType(node: Node): string | undefined {