Skip to content

Commit 4496456

Browse files
committed
feat(compiler-sfc): support dynamic imports when resolving types
1 parent 7c3ca3c commit 4496456

File tree

2 files changed

+70
-23
lines changed

2 files changed

+70
-23
lines changed

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

+18
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,24 @@ describe('resolveType', () => {
472472
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
473473
})
474474

475+
test('relative (dynamic import)', () => {
476+
const files = {
477+
'/foo.ts': `export type P = { foo: string, bar: import('./bar').N }`,
478+
'/bar.ts': 'export type N = number'
479+
}
480+
const { props, deps } = resolve(
481+
`
482+
defineProps<import('./foo').P>()
483+
`,
484+
files
485+
)
486+
expect(props).toStrictEqual({
487+
foo: ['String'],
488+
bar: ['Number']
489+
})
490+
expect(deps && [...deps]).toStrictEqual(Object.keys(files))
491+
})
492+
475493
test('ts module resolve', () => {
476494
const files = {
477495
'/node_modules/foo/package.json': JSON.stringify({

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

+52-23
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
TSEnumDeclaration,
88
TSExpressionWithTypeArguments,
99
TSFunctionType,
10+
TSImportType,
1011
TSIndexedAccessType,
1112
TSInterfaceDeclaration,
1213
TSMappedType,
@@ -168,6 +169,17 @@ function innerResolveTypeElements(
168169
)
169170
}
170171
}
172+
case 'TSImportType':
173+
const sourceScope = importSourceToScope(
174+
ctx,
175+
node.argument,
176+
scope,
177+
node.argument.value
178+
)
179+
const resolved = resolveTypeReference(ctx, node, sourceScope)
180+
if (resolved) {
181+
return resolveTypeElements(ctx, resolved, resolved._ownerScope)
182+
}
171183
}
172184
return ctx.error(`Unresolvable type: ${node.type}`, node, scope)
173185
}
@@ -486,9 +498,14 @@ function resolveBuiltin(
486498
}
487499
}
488500

501+
type ReferenceTypes =
502+
| TSTypeReference
503+
| TSExpressionWithTypeArguments
504+
| TSImportType
505+
489506
function resolveTypeReference(
490507
ctx: TypeResolveContext,
491-
node: (TSTypeReference | TSExpressionWithTypeArguments) & {
508+
node: ReferenceTypes & {
492509
_resolvedReference?: ScopeTypeNode
493510
},
494511
scope?: TypeScope,
@@ -511,7 +528,7 @@ function innerResolveTypeReference(
511528
ctx: TypeResolveContext,
512529
scope: TypeScope,
513530
name: string | string[],
514-
node: TSTypeReference | TSExpressionWithTypeArguments,
531+
node: ReferenceTypes,
515532
onlyExported: boolean
516533
): ScopeTypeNode | undefined {
517534
if (typeof name === 'string') {
@@ -555,11 +572,16 @@ function innerResolveTypeReference(
555572
}
556573
}
557574

558-
function getReferenceName(
559-
node: TSTypeReference | TSExpressionWithTypeArguments
560-
): string | string[] {
561-
const ref = node.type === 'TSTypeReference' ? node.typeName : node.expression
562-
if (ref.type === 'Identifier') {
575+
function getReferenceName(node: ReferenceTypes): string | string[] {
576+
const ref =
577+
node.type === 'TSTypeReference'
578+
? node.typeName
579+
: node.type === 'TSExpressionWithTypeArguments'
580+
? node.expression
581+
: node.qualifier
582+
if (!ref) {
583+
return 'default'
584+
} else if (ref.type === 'Identifier') {
563585
return ref.name
564586
} else {
565587
return qualifiedNameToPath(ref)
@@ -599,27 +621,21 @@ type FS = NonNullable<SFCScriptCompileOptions['fs']>
599621

600622
function resolveTypeFromImport(
601623
ctx: TypeResolveContext,
602-
node: TSTypeReference | TSExpressionWithTypeArguments,
624+
node: ReferenceTypes,
603625
name: string,
604626
scope: TypeScope
605627
): ScopeTypeNode | undefined {
606628
const { source, imported } = scope.imports[name]
607-
const resolved = resolveImportSource(ctx, node, scope, source)
608-
return resolveTypeReference(
609-
ctx,
610-
node,
611-
fileToScope(ctx, resolved),
612-
imported,
613-
true
614-
)
629+
const sourceScope = importSourceToScope(ctx, node, scope, source)
630+
return resolveTypeReference(ctx, node, sourceScope, imported, true)
615631
}
616632

617-
function resolveImportSource(
633+
function importSourceToScope(
618634
ctx: TypeResolveContext,
619635
node: Node,
620636
scope: TypeScope,
621637
source: string
622-
): string {
638+
): TypeScope {
623639
const fs: FS = ctx.options.fs || ts?.sys
624640
if (!fs) {
625641
ctx.error(
@@ -657,7 +673,7 @@ function resolveImportSource(
657673
if (resolved) {
658674
// (hmr) register dependency file on ctx
659675
;(ctx.deps || (ctx.deps = new Set())).add(resolved)
660-
return normalizePath(resolved)
676+
return fileToScope(ctx, normalizePath(resolved))
661677
} else {
662678
return ctx.error(
663679
`Failed to resolve import source ${JSON.stringify(source)}.`,
@@ -938,14 +954,13 @@ function recordTypes(
938954
}
939955
}
940956
} else if (stmt.type === 'ExportAllDeclaration') {
941-
const targetFile = resolveImportSource(
957+
const sourceScope = importSourceToScope(
942958
ctx,
943959
stmt.source,
944960
scope,
945961
stmt.source.value
946962
)
947-
const targetScope = fileToScope(ctx, targetFile)
948-
Object.assign(scope.exportedTypes, targetScope.exportedTypes)
963+
Object.assign(scope.exportedTypes, sourceScope.exportedTypes)
949964
}
950965
}
951966
}
@@ -1134,7 +1149,7 @@ export function inferRuntimeType(
11341149
return [UNKNOWN_TYPE]
11351150
}
11361151

1137-
case 'TSTypeReference':
1152+
case 'TSTypeReference': {
11381153
const resolved = resolveTypeReference(ctx, node, scope)
11391154
if (resolved) {
11401155
return inferRuntimeType(ctx, resolved, resolved._ownerScope)
@@ -1197,6 +1212,7 @@ export function inferRuntimeType(
11971212
}
11981213
// cannot infer, fallback to UNKNOWN: ThisParameterType
11991214
return [UNKNOWN_TYPE]
1215+
}
12001216

12011217
case 'TSParenthesizedType':
12021218
return inferRuntimeType(ctx, node.typeAnnotation, scope)
@@ -1228,6 +1244,19 @@ export function inferRuntimeType(
12281244
case 'ClassDeclaration':
12291245
return ['Object']
12301246

1247+
case 'TSImportType': {
1248+
const sourceScope = importSourceToScope(
1249+
ctx,
1250+
node.argument,
1251+
scope,
1252+
node.argument.value
1253+
)
1254+
const resolved = resolveTypeReference(ctx, node, sourceScope)
1255+
if (resolved) {
1256+
return inferRuntimeType(ctx, resolved, resolved._ownerScope)
1257+
}
1258+
}
1259+
12311260
default:
12321261
return [UNKNOWN_TYPE] // no runtime check
12331262
}

0 commit comments

Comments
 (0)