feat(compiler-sfc): improve runtime props inference for enum

This commit is contained in:
Evan You 2023-03-28 17:29:31 +08:00
parent 5fb406e3e1
commit eded94712e
2 changed files with 78 additions and 7 deletions

View File

@ -1573,6 +1573,56 @@ const emit = defineEmits(['a', 'b'])
}) })
}) })
test('runtime inference for Enum in defineProps', () => {
expect(
compile(
`<script setup lang="ts">
const enum Foo { A = 123 }
defineProps<{
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
).toMatch(`foo: { type: Number`)
expect(
compile(
`<script setup lang="ts">
const enum Foo { A = '123' }
defineProps<{
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
).toMatch(`foo: { type: String`)
expect(
compile(
`<script setup lang="ts">
const enum Foo { A = '123', B = 123 }
defineProps<{
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
).toMatch(`foo: { type: [String, Number]`)
expect(
compile(
`<script setup lang="ts">
const enum Foo { A, B }
defineProps<{
foo: Foo
}>()
</script>`,
{ hoistStatic: true }
).content
).toMatch(`foo: { type: Number`)
})
test('import type', () => { test('import type', () => {
const { content } = compile( const { content } = compile(
`<script setup lang="ts"> `<script setup lang="ts">

View File

@ -44,7 +44,8 @@ import {
ObjectMethod, ObjectMethod,
LVal, LVal,
Expression, Expression,
VariableDeclaration VariableDeclaration,
TSEnumDeclaration
} from '@babel/types' } from '@babel/types'
import { walk } from 'estree-walker' import { walk } from 'estree-walker'
import { RawSourceMap } from 'source-map' import { RawSourceMap } from 'source-map'
@ -1369,17 +1370,18 @@ export function compileScript(
if (isTS) { if (isTS) {
// move all Type declarations to outer scope // move all Type declarations to outer scope
if ( if (
(node.type.startsWith('TS') || node.type.startsWith('TS') ||
(node.type === 'ExportNamedDeclaration' && (node.type === 'ExportNamedDeclaration' &&
node.exportKind === 'type') || node.exportKind === 'type') ||
(node.type === 'VariableDeclaration' && node.declare)) && (node.type === 'VariableDeclaration' && node.declare)
node.type !== 'TSEnumDeclaration'
) { ) {
recordType(node, declaredTypes) recordType(node, declaredTypes)
if (node.type !== 'TSEnumDeclaration') {
hoistNode(node) hoistNode(node)
} }
} }
} }
}
// 3. Apply reactivity transform // 3. Apply reactivity transform
if ( if (
@ -1966,6 +1968,8 @@ function recordType(node: Node, declaredTypes: Record<string, string[]>) {
) )
} else if (node.type === 'ExportNamedDeclaration' && node.declaration) { } else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
recordType(node.declaration, declaredTypes) recordType(node.declaration, declaredTypes)
} else if (node.type === 'TSEnumDeclaration') {
declaredTypes[node.id.name] = inferEnumType(node)
} }
} }
@ -2152,6 +2156,23 @@ function toRuntimeTypeString(types: string[]) {
return types.length > 1 ? `[${types.join(', ')}]` : types[0] return types.length > 1 ? `[${types.join(', ')}]` : types[0]
} }
function inferEnumType(node: TSEnumDeclaration): string[] {
const types = new Set<string>()
for (const m of node.members) {
if (m.initializer) {
switch (m.initializer.type) {
case 'StringLiteral':
types.add('String')
break
case 'NumericLiteral':
types.add('Number')
break
}
}
}
return types.size ? [...types] : ['Number']
}
function extractRuntimeEmits( function extractRuntimeEmits(
node: TSFunctionType | TSTypeLiteral | TSInterfaceBody, node: TSFunctionType | TSTypeLiteral | TSInterfaceBody,
emits: Set<string> emits: Set<string>