]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compile-sfc): support use other prop as default value in props destructuring edison/fix/12386 12387/head
authordaiwei <daiwei521@126.com>
Thu, 14 Nov 2024 02:13:50 +0000 (10:13 +0800)
committerdaiwei <daiwei521@126.com>
Thu, 14 Nov 2024 02:13:50 +0000 (10:13 +0800)
packages/compiler-sfc/__tests__/compileScript/__snapshots__/definePropsDestructure.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript/definePropsDestructure.spec.ts
packages/compiler-sfc/src/script/defineProps.ts

index 1044b0e167cbdd12e57de493d59cde1c2f71539d..2957a42292a4a06bf429fd2da96edc4e35504ebc 100644 (file)
@@ -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 () => {}
 }
index 50602eb59bc0fa607d36e3507ff3eca7551f0322..de242e914521a7547550e8a6b6036506229e16b3 100644 (file)
@@ -106,25 +106,28 @@ describe('sfc reactive props destructure', () => {
 })`)
     assertCode(content)
   })
+
   test('default values w/ runtime declaration & key is string', () => {
     const { content, bindings } = compile(`
       <script setup>
-      const { foo = 1, 'foo:bar': fooBar = 'foo-bar' } = defineProps(['foo', 'foo:bar'])
+      const { foo = 1, 'foo:bar': fooBar = 'foo-bar', baz = foo } = defineProps(['foo', 'foo:bar', 'baz'])
       </script>
     `)
     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(`
       <script setup lang="ts">
-      const { foo = 1, bar = {}, func = () => {} } = defineProps<{ foo?: number, bar?: object, func?: () => any }>()
+      const { foo = 1, bar = {}, func = () => {}, baz = bar } = defineProps<{ foo?: number, bar?: object, func?: () => any, baz?: object }>()
       </script>
     `)
     // 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)
   })
index 9a4880a1a543f20f601b44c672df817d024aabc7..a89c89769b723f62343f2b8d4ef7a3ffa1fd968b 100644 (file)
@@ -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 {