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', () => {
const { content } = compile(
`<script setup lang="ts">

View File

@ -44,7 +44,8 @@ import {
ObjectMethod,
LVal,
Expression,
VariableDeclaration
VariableDeclaration,
TSEnumDeclaration
} from '@babel/types'
import { walk } from 'estree-walker'
import { RawSourceMap } from 'source-map'
@ -1369,14 +1370,15 @@ export function compileScript(
if (isTS) {
// move all Type declarations to outer scope
if (
(node.type.startsWith('TS') ||
(node.type === 'ExportNamedDeclaration' &&
node.exportKind === 'type') ||
(node.type === 'VariableDeclaration' && node.declare)) &&
node.type !== 'TSEnumDeclaration'
node.type.startsWith('TS') ||
(node.type === 'ExportNamedDeclaration' &&
node.exportKind === 'type') ||
(node.type === 'VariableDeclaration' && node.declare)
) {
recordType(node, declaredTypes)
hoistNode(node)
if (node.type !== 'TSEnumDeclaration') {
hoistNode(node)
}
}
}
}
@ -1966,6 +1968,8 @@ function recordType(node: Node, declaredTypes: Record<string, string[]>) {
)
} else if (node.type === 'ExportNamedDeclaration' && node.declaration) {
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]
}
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(
node: TSFunctionType | TSTypeLiteral | TSInterfaceBody,
emits: Set<string>