This commit is contained in:
edison 2025-06-27 09:38:29 +02:00 committed by GitHub
commit 93f67546a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 26 additions and 13 deletions

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

View 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)
})

View 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 {