diff --git a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineEmits.spec.ts.snap b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineEmits.spec.ts.snap
index 729c019a555..a8bd930fbbc 100644
--- a/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineEmits.spec.ts.snap
+++ b/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineEmits.spec.ts.snap
@@ -191,6 +191,24 @@ export default /*#__PURE__*/_defineComponent({
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (type references in union) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+type BaseEmit = \\"change\\"
+ type Emit = \\"some\\" | \\"emit\\" | BaseEmit
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"some\\", \\"emit\\", \\"change\\", \\"another\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
return { emit }
}
diff --git a/packages/compiler-sfc/__tests__/compileScript/defineEmits.spec.ts b/packages/compiler-sfc/__tests__/compileScript/defineEmits.spec.ts
index 67d9674b54c..c5d2900a4e7 100644
--- a/packages/compiler-sfc/__tests__/compileScript/defineEmits.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript/defineEmits.spec.ts
@@ -179,6 +179,23 @@ const emit = defineEmits(['a', 'b'])
assertCode(content)
})
+ // #7943
+ test('w/ type (type references in union)', () => {
+ const { content } = compile(`
+
+ `)
+
+ expect(content).toMatch(`emits: ["some", "emit", "change", "another"]`)
+ assertCode(content)
+ })
+
describe('errors', () => {
test('w/ both type and non-type args', () => {
expect(() => {
diff --git a/packages/compiler-sfc/src/script/defineEmits.ts b/packages/compiler-sfc/src/script/defineEmits.ts
index e615cd71a0d..a50cf91fc4a 100644
--- a/packages/compiler-sfc/src/script/defineEmits.ts
+++ b/packages/compiler-sfc/src/script/defineEmits.ts
@@ -1,7 +1,7 @@
import { Identifier, LVal, Node, RestElement } from '@babel/types'
import { isCallOf } from './utils'
import { ScriptCompileContext } from './context'
-import { resolveTypeElements } from './resolveType'
+import { resolveTypeElements, resolveUnionType } from './resolveType'
export const DEFINE_EMITS = 'defineEmits'
@@ -65,7 +65,7 @@ function extractRuntimeEmits(ctx: ScriptCompileContext): Set {
const node = ctx.emitsTypeDecl!
if (node.type === 'TSFunctionType') {
- extractEventNames(node.parameters[0], emits)
+ extractEventNames(ctx, node.parameters[0], emits)
return emits
}
@@ -85,7 +85,7 @@ function extractRuntimeEmits(ctx: ScriptCompileContext): Set {
)
}
for (const call of calls) {
- extractEventNames(call.parameters[0], emits)
+ extractEventNames(ctx, call.parameters[0], emits)
}
}
@@ -93,6 +93,7 @@ function extractRuntimeEmits(ctx: ScriptCompileContext): Set {
}
function extractEventNames(
+ ctx: ScriptCompileContext,
eventName: Identifier | RestElement,
emits: Set
) {
@@ -101,22 +102,15 @@ function extractEventNames(
eventName.typeAnnotation &&
eventName.typeAnnotation.type === 'TSTypeAnnotation'
) {
- const typeNode = eventName.typeAnnotation.typeAnnotation
- if (typeNode.type === 'TSLiteralType') {
- if (
- typeNode.literal.type !== 'UnaryExpression' &&
- typeNode.literal.type !== 'TemplateLiteral'
- ) {
- emits.add(String(typeNode.literal.value))
- }
- } else if (typeNode.type === 'TSUnionType') {
- for (const t of typeNode.types) {
+ const types = resolveUnionType(ctx, eventName.typeAnnotation.typeAnnotation)
+
+ for (const type of types) {
+ if (type.type === 'TSLiteralType') {
if (
- t.type === 'TSLiteralType' &&
- t.literal.type !== 'UnaryExpression' &&
- t.literal.type !== 'TemplateLiteral'
+ type.literal.type !== 'UnaryExpression' &&
+ type.literal.type !== 'TemplateLiteral'
) {
- emits.add(String(t.literal.value))
+ emits.add(String(type.literal.value))
}
}
}
diff --git a/packages/compiler-sfc/src/script/resolveType.ts b/packages/compiler-sfc/src/script/resolveType.ts
index e79d21f8419..0f6514d2628 100644
--- a/packages/compiler-sfc/src/script/resolveType.ts
+++ b/packages/compiler-sfc/src/script/resolveType.ts
@@ -1605,3 +1605,23 @@ function resolveReturnType(
return resolved.returnType
}
}
+
+export function resolveUnionType(
+ ctx: TypeResolveContext,
+ node: Node & MaybeWithScope & { _resolvedElements?: ResolvedElements },
+ scope?: TypeScope
+): Node[] {
+ if (node.type === 'TSTypeReference') {
+ const resolved = resolveTypeReference(ctx, node, scope)
+ if (resolved) node = resolved
+ }
+
+ let types: Node[]
+ if (node.type === 'TSUnionType') {
+ types = node.types.flatMap(node => resolveUnionType(ctx, node, scope))
+ } else {
+ types = [node]
+ }
+
+ return types
+}