+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 }
}
assertCode(content)
})
+ // #7943
+ test('w/ type (type references in union)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ type BaseEmit = "change"
+ type Emit = "some" | "emit" | BaseEmit
+ const emit = defineEmits<{
+ (e: Emit): void;
+ (e: "another", val: string): void;
+ }>();
+ </script>
+ `)
+
+ expect(content).toMatch(`emits: ["some", "emit", "change", "another"]`)
+ assertCode(content)
+ })
+
describe('errors', () => {
test('w/ both type and non-type args', () => {
expect(() => {
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'
const node = ctx.emitsTypeDecl!
if (node.type === 'TSFunctionType') {
- extractEventNames(node.parameters[0], emits)
+ extractEventNames(ctx, node.parameters[0], emits)
return emits
}
)
}
for (const call of calls) {
- extractEventNames(call.parameters[0], emits)
+ extractEventNames(ctx, call.parameters[0], emits)
}
}
}
function extractEventNames(
+ ctx: ScriptCompileContext,
eventName: Identifier | RestElement,
emits: Set<string>
) {
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))
}
}
}
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
+}