Skip to content

Commit d9dd628

Browse files
authored
fix(compiler-sfc): improve type inference for generic type aliases types (#12876)
close #12872
1 parent 4a2953f commit d9dd628

File tree

2 files changed

+61
-18
lines changed

2 files changed

+61
-18
lines changed

packages/compiler-sfc/__tests__/compileScript/resolveType.spec.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ describe('resolveType', () => {
538538

539539
expect(props).toStrictEqual({
540540
foo: ['Symbol', 'String', 'Number'],
541-
bar: [UNKNOWN_TYPE],
541+
bar: ['String', 'Number'],
542542
})
543543
})
544544

@@ -749,7 +749,7 @@ describe('resolveType', () => {
749749
})
750750
})
751751

752-
test('fallback to Unknown', () => {
752+
test('with intersection type', () => {
753753
expect(
754754
resolve(`
755755
type Brand<T> = T & {};
@@ -758,7 +758,18 @@ describe('resolveType', () => {
758758
}>()
759759
`).props,
760760
).toStrictEqual({
761-
foo: [UNKNOWN_TYPE],
761+
foo: ['String', 'Object'],
762+
})
763+
})
764+
765+
test('with union type', () => {
766+
expect(
767+
resolve(`
768+
type Wrapped<T> = T | symbol | number
769+
defineProps<{foo?: Wrapped<boolean>}>()
770+
`).props,
771+
).toStrictEqual({
772+
foo: ['Boolean', 'Symbol', 'Number'],
762773
})
763774
})
764775
})

packages/compiler-sfc/src/script/resolveType.ts

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,7 @@ export function inferRuntimeType(
15001500
node: Node & MaybeWithScope,
15011501
scope: TypeScope = node._ownerScope || ctxToScope(ctx),
15021502
isKeyOf = false,
1503+
typeParameters?: Record<string, Node>,
15031504
): string[] {
15041505
try {
15051506
switch (node.type) {
@@ -1588,19 +1589,43 @@ export function inferRuntimeType(
15881589
case 'TSTypeReference': {
15891590
const resolved = resolveTypeReference(ctx, node, scope)
15901591
if (resolved) {
1591-
// #13240
1592-
// Special case for function type aliases to ensure correct runtime behavior
1593-
// other type aliases still fallback to unknown as before
1594-
if (
1595-
resolved.type === 'TSTypeAliasDeclaration' &&
1596-
resolved.typeAnnotation.type === 'TSFunctionType'
1597-
) {
1598-
return ['Function']
1592+
if (resolved.type === 'TSTypeAliasDeclaration') {
1593+
// #13240
1594+
// Special case for function type aliases to ensure correct runtime behavior
1595+
// other type aliases still fallback to unknown as before
1596+
if (resolved.typeAnnotation.type === 'TSFunctionType') {
1597+
return ['Function']
1598+
}
1599+
1600+
if (node.typeParameters) {
1601+
const typeParams: Record<string, Node> = Object.create(null)
1602+
if (resolved.typeParameters) {
1603+
resolved.typeParameters.params.forEach((p, i) => {
1604+
typeParams![p.name] = node.typeParameters!.params[i]
1605+
})
1606+
}
1607+
return inferRuntimeType(
1608+
ctx,
1609+
resolved.typeAnnotation,
1610+
resolved._ownerScope,
1611+
isKeyOf,
1612+
typeParams,
1613+
)
1614+
}
15991615
}
1616+
16001617
return inferRuntimeType(ctx, resolved, resolved._ownerScope, isKeyOf)
16011618
}
1602-
16031619
if (node.typeName.type === 'Identifier') {
1620+
if (typeParameters && typeParameters[node.typeName.name]) {
1621+
return inferRuntimeType(
1622+
ctx,
1623+
typeParameters[node.typeName.name],
1624+
scope,
1625+
isKeyOf,
1626+
typeParameters,
1627+
)
1628+
}
16041629
if (isKeyOf) {
16051630
switch (node.typeName.name) {
16061631
case 'String':
@@ -1733,11 +1758,15 @@ export function inferRuntimeType(
17331758
return inferRuntimeType(ctx, node.typeAnnotation, scope)
17341759

17351760
case 'TSUnionType':
1736-
return flattenTypes(ctx, node.types, scope, isKeyOf)
1761+
return flattenTypes(ctx, node.types, scope, isKeyOf, typeParameters)
17371762
case 'TSIntersectionType': {
1738-
return flattenTypes(ctx, node.types, scope, isKeyOf).filter(
1739-
t => t !== UNKNOWN_TYPE,
1740-
)
1763+
return flattenTypes(
1764+
ctx,
1765+
node.types,
1766+
scope,
1767+
isKeyOf,
1768+
typeParameters,
1769+
).filter(t => t !== UNKNOWN_TYPE)
17411770
}
17421771

17431772
case 'TSEnumDeclaration':
@@ -1808,14 +1837,17 @@ function flattenTypes(
18081837
types: TSType[],
18091838
scope: TypeScope,
18101839
isKeyOf: boolean = false,
1840+
typeParameters: Record<string, Node> | undefined = undefined,
18111841
): string[] {
18121842
if (types.length === 1) {
1813-
return inferRuntimeType(ctx, types[0], scope, isKeyOf)
1843+
return inferRuntimeType(ctx, types[0], scope, isKeyOf, typeParameters)
18141844
}
18151845
return [
18161846
...new Set(
18171847
([] as string[]).concat(
1818-
...types.map(t => inferRuntimeType(ctx, t, scope, isKeyOf)),
1848+
...types.map(t =>
1849+
inferRuntimeType(ctx, t, scope, isKeyOf, typeParameters),
1850+
),
18191851
),
18201852
),
18211853
]

0 commit comments

Comments
 (0)