]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): support defineEmits type reference with unions (#8299)
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Thu, 18 May 2023 04:59:12 +0000 (12:59 +0800)
committerGitHub <noreply@github.com>
Thu, 18 May 2023 04:59:12 +0000 (12:59 +0800)
close #7943

packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineEmits.spec.ts.snap
packages/compiler-sfc/__tests__/compileScript/defineEmits.spec.ts
packages/compiler-sfc/src/script/defineEmits.ts
packages/compiler-sfc/src/script/resolveType.ts

index 729c019a555b9d404538453cc6505b4af6aef6c2..a8bd930fbbcca0cd40a7de8870959e635f848505 100644 (file)
@@ -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 }
 }
 
index 67d9674b54ce46ceac96166159967ac3340cf7bf..c5d2900a4e75fc983793600c8255ab1195b6dad7 100644 (file)
@@ -179,6 +179,23 @@ const emit = defineEmits(['a', 'b'])
     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(() => {
index e615cd71a0dd87a2c25efa6f8c9c6db73cf4612e..a50cf91fc4aa8d319f032ef05fe4dbff6ca218a6 100644 (file)
@@ -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<string> {
   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<string> {
       )
     }
     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<string> {
 }
 
 function extractEventNames(
+  ctx: ScriptCompileContext,
   eventName: Identifier | RestElement,
   emits: Set<string>
 ) {
@@ -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))
         }
       }
     }
index 83d4fbfc887053f402597a6c2062b5e84812b2ea..775aa41ff83101ab86552ee55780390b6af8a02c 100644 (file)
@@ -1637,3 +1637,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
+}