Skip to content

Commit

Permalink
fix(compiler-sfc): support defineEmits type reference with unions (#8299
Browse files Browse the repository at this point in the history
)

close #7943
  • Loading branch information
sxzz committed May 18, 2023
1 parent 17d37d6 commit b133e0f
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 17 deletions.
Expand Up @@ -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 }
}
Expand Down
17 changes: 17 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript/defineEmits.spec.ts
Expand Up @@ -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(() => {
Expand Down
28 changes: 11 additions & 17 deletions 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'

Expand Down Expand Up @@ -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
}

Expand All @@ -85,14 +85,15 @@ function extractRuntimeEmits(ctx: ScriptCompileContext): Set<string> {
)
}
for (const call of calls) {
extractEventNames(call.parameters[0], emits)
extractEventNames(ctx, call.parameters[0], emits)
}
}

return emits
}

function extractEventNames(
ctx: ScriptCompileContext,
eventName: Identifier | RestElement,
emits: Set<string>
) {
Expand All @@ -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))
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions packages/compiler-sfc/src/script/resolveType.ts
Expand Up @@ -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
}

0 comments on commit b133e0f

Please sign in to comment.