Przeglądaj źródła

fix(compile-sfc): support use other prop as default value in props destructuring

daiwei 1 rok temu
rodzic
commit
038dc1eefe

+ 7 - 5
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 () => {}
 }

+ 9 - 5
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(`
       <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)
   })

+ 10 - 3
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 {