feat(compiler-sfc): codegen support for defineEmits() short syntax (followup of #7992)

This commit is contained in:
Evan You 2023-03-30 19:59:07 +08:00
parent 8876dccf42
commit ef73ea53ea
3 changed files with 58 additions and 2 deletions

View File

@ -1478,6 +1478,22 @@ export default /*#__PURE__*/_defineComponent({
return { emit }
}
})"
`;
exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (tuple syntax) 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
setup(__props, { expose: __expose, emit }: { emit: ({ foo: [], bar: [] }), expose: any, slots: any, attrs: any }) {
__expose();
return { emit } return { emit }
} }

View File

@ -1540,6 +1540,16 @@ const emit = defineEmits(['a', 'b'])
expect(content).toMatch(`emits: ['foo']`) expect(content).toMatch(`emits: ['foo']`)
}) })
test('defineEmits w/ type (tuple syntax)', () => {
const { content } = compile(`
<script setup lang="ts">
const emit = defineEmits<{ foo: [], bar: [] }>()
</script>
`)
expect(content).toMatch(`emits: ["foo", "bar"]`)
assertCode(content)
})
test('runtime Enum', () => { test('runtime Enum', () => {
const { content, bindings } = compile( const { content, bindings } = compile(
`<script setup lang="ts"> `<script setup lang="ts">
@ -1871,6 +1881,19 @@ const emit = defineEmits(['a', 'b'])
</script>`).content </script>`).content
) )
}) })
test('mixed usage of tuple / call signature in defineEmits', () => {
expect(() =>
compile(`<script setup lang="ts">
defineEmits<{
foo: []
(e: 'hi'): void
}>()
</script>`)
).toThrow(
`defineEmits() type cannot mixed call signature and property syntax.`
)
})
}) })
}) })

View File

@ -1486,7 +1486,7 @@ export function compileScript(
extractRuntimeProps(propsTypeDecl, typeDeclaredProps, declaredTypes) extractRuntimeProps(propsTypeDecl, typeDeclaredProps, declaredTypes)
} }
if (emitsTypeDecl) { if (emitsTypeDecl) {
extractRuntimeEmits(emitsTypeDecl, typeDeclaredEmits) extractRuntimeEmits(emitsTypeDecl, typeDeclaredEmits, error)
} }
// 5. check macro args to make sure it doesn't reference setup scope // 5. check macro args to make sure it doesn't reference setup scope
@ -2289,14 +2289,31 @@ function inferValueType(node: Node): string | undefined {
function extractRuntimeEmits( function extractRuntimeEmits(
node: TSFunctionType | TSTypeLiteral | TSInterfaceBody, node: TSFunctionType | TSTypeLiteral | TSInterfaceBody,
emits: Set<string> emits: Set<string>,
error: (msg: string, node: Node) => never
) { ) {
if (node.type === 'TSTypeLiteral' || node.type === 'TSInterfaceBody') { if (node.type === 'TSTypeLiteral' || node.type === 'TSInterfaceBody') {
const members = node.type === 'TSTypeLiteral' ? node.members : node.body const members = node.type === 'TSTypeLiteral' ? node.members : node.body
let hasCallSignature = false
let hasProperty = false
for (let t of members) { for (let t of members) {
if (t.type === 'TSCallSignatureDeclaration') { if (t.type === 'TSCallSignatureDeclaration') {
extractEventNames(t.parameters[0], emits) extractEventNames(t.parameters[0], emits)
hasCallSignature = true
} }
if (t.type === 'TSPropertySignature') {
if (t.key.type !== 'Identifier' || t.computed) {
error(`defineEmits() type cannot use computed keys.`, t.key)
}
emits.add(t.key.name)
hasProperty = true
}
}
if (hasCallSignature && hasProperty) {
error(
`defineEmits() type cannot mixed call signature and property syntax.`,
node
)
} }
return return
} else { } else {