@@ -60,6 +60,8 @@ namespace ts.Completions {
60
60
ThisProperty = "ThisProperty/" ,
61
61
/** Auto-import that comes attached to a class member snippet */
62
62
ClassMemberSnippet = "ClassMemberSnippet/" ,
63
+ /** A type-only import that needs to be promoted in order to be used at the completion location */
64
+ TypeOnlyAlias = "TypeOnlyAlias/" ,
63
65
}
64
66
65
67
const enum SymbolOriginInfoKind {
@@ -69,6 +71,7 @@ namespace ts.Completions {
69
71
Promise = 1 << 3 ,
70
72
Nullable = 1 << 4 ,
71
73
ResolvedExport = 1 << 5 ,
74
+ TypeOnlyAlias = 1 << 6 ,
72
75
73
76
SymbolMemberNoExport = SymbolMember ,
74
77
SymbolMemberExport = SymbolMember | Export ,
@@ -96,6 +99,10 @@ namespace ts.Completions {
96
99
moduleSpecifier : string ;
97
100
}
98
101
102
+ interface SymbolOriginInfoTypeOnlyAlias extends SymbolOriginInfo {
103
+ declaration : TypeOnlyAliasDeclaration ;
104
+ }
105
+
99
106
function originIsThisType ( origin : SymbolOriginInfo ) : boolean {
100
107
return ! ! ( origin . kind & SymbolOriginInfoKind . ThisType ) ;
101
108
}
@@ -128,6 +135,10 @@ namespace ts.Completions {
128
135
return ! ! ( origin . kind & SymbolOriginInfoKind . Nullable ) ;
129
136
}
130
137
138
+ function originIsTypeOnlyAlias ( origin : SymbolOriginInfo | undefined ) : origin is SymbolOriginInfoTypeOnlyAlias {
139
+ return ! ! ( origin && origin . kind & SymbolOriginInfoKind . TypeOnlyAlias ) ;
140
+ }
141
+
131
142
interface UniqueNameSet {
132
143
add ( name : string ) : void ;
133
144
has ( name : string ) : boolean ;
@@ -740,6 +751,10 @@ namespace ts.Completions {
740
751
}
741
752
}
742
753
754
+ if ( origin ?. kind === SymbolOriginInfoKind . TypeOnlyAlias ) {
755
+ hasAction = true ;
756
+ }
757
+
743
758
if ( preferences . includeCompletionsWithClassMemberSnippets &&
744
759
preferences . includeCompletionsWithInsertText &&
745
760
completionKind === CompletionKind . MemberLike &&
@@ -1168,6 +1183,9 @@ namespace ts.Completions {
1168
1183
if ( origin ?. kind === SymbolOriginInfoKind . ThisType ) {
1169
1184
return CompletionSource . ThisProperty ;
1170
1185
}
1186
+ if ( origin ?. kind === SymbolOriginInfoKind . TypeOnlyAlias ) {
1187
+ return CompletionSource . TypeOnlyAlias ;
1188
+ }
1171
1189
}
1172
1190
1173
1191
export function getCompletionEntriesFromSymbols (
@@ -1245,7 +1263,7 @@ namespace ts.Completions {
1245
1263
}
1246
1264
1247
1265
/** True for locals; false for globals, module exports from other files, `this.` completions. */
1248
- const shouldShadowLaterSymbols = ! origin && ! ( symbol . parent === undefined && ! some ( symbol . declarations , d => d . getSourceFile ( ) === location . getSourceFile ( ) ) ) ;
1266
+ const shouldShadowLaterSymbols = ( ! origin || originIsTypeOnlyAlias ( origin ) ) && ! ( symbol . parent === undefined && ! some ( symbol . declarations , d => d . getSourceFile ( ) === location . getSourceFile ( ) ) ) ;
1249
1267
uniques . set ( name , shouldShadowLaterSymbols ) ;
1250
1268
insertSorted ( entries , entry , compareCompletionEntries , /*allowDuplicates*/ true ) ;
1251
1269
}
@@ -1261,6 +1279,7 @@ namespace ts.Completions {
1261
1279
} ;
1262
1280
1263
1281
function shouldIncludeSymbol ( symbol : Symbol , symbolToSortTextIdMap : SymbolSortTextIdMap ) : boolean {
1282
+ let allFlags = symbol . flags ;
1264
1283
if ( ! isSourceFile ( location ) ) {
1265
1284
// export = /**/ here we want to get all meanings, so any symbol is ok
1266
1285
if ( isExportAssignment ( location . parent ) ) {
@@ -1287,12 +1306,12 @@ namespace ts.Completions {
1287
1306
|| symbolToSortTextIdMap [ getSymbolId ( symbolOrigin ) ] === SortTextId . LocationPriority ) ) {
1288
1307
return false ;
1289
1308
}
1290
- // Continue with origin symbol
1291
- symbol = symbolOrigin ;
1309
+
1310
+ allFlags |= getCombinedLocalAndExportSymbolFlags ( symbolOrigin ) ;
1292
1311
1293
1312
// import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
1294
1313
if ( isInRightSideOfInternalImportEqualsDeclaration ( location ) ) {
1295
- return ! ! ( symbol . flags & SymbolFlags . Namespace ) ;
1314
+ return ! ! ( allFlags & SymbolFlags . Namespace ) ;
1296
1315
}
1297
1316
1298
1317
if ( isTypeOnlyLocation ) {
@@ -1302,7 +1321,7 @@ namespace ts.Completions {
1302
1321
}
1303
1322
1304
1323
// expressions are value space (which includes the value namespaces)
1305
- return ! ! ( getCombinedLocalAndExportSymbolFlags ( symbol ) & SymbolFlags . Value ) ;
1324
+ return ! ! ( allFlags & SymbolFlags . Value ) ;
1306
1325
}
1307
1326
}
1308
1327
@@ -1533,6 +1552,19 @@ namespace ts.Completions {
1533
1552
}
1534
1553
}
1535
1554
1555
+ if ( originIsTypeOnlyAlias ( origin ) ) {
1556
+ const codeAction = codefix . getPromoteTypeOnlyCompletionAction (
1557
+ sourceFile ,
1558
+ origin . declaration . name ,
1559
+ program ,
1560
+ host ,
1561
+ formatContext ,
1562
+ preferences ) ;
1563
+
1564
+ Debug . assertIsDefined ( codeAction , "Expected to have a code action for promoting type-only alias" ) ;
1565
+ return { codeActions : [ codeAction ] , sourceDisplay : undefined } ;
1566
+ }
1567
+
1536
1568
if ( ! origin || ! ( originIsExport ( origin ) || originIsResolvedExport ( origin ) ) ) {
1537
1569
return { codeActions : undefined , sourceDisplay : undefined } ;
1538
1570
}
@@ -2314,14 +2346,23 @@ namespace ts.Completions {
2314
2346
isInSnippetScope = isSnippetScope ( scopeNode ) ;
2315
2347
2316
2348
const symbolMeanings = ( isTypeOnlyLocation ? SymbolFlags . None : SymbolFlags . Value ) | SymbolFlags . Type | SymbolFlags . Namespace | SymbolFlags . Alias ;
2349
+ const typeOnlyAliasNeedsPromotion = previousToken && ! isValidTypeOnlyAliasUseSite ( previousToken ) ;
2317
2350
2318
2351
symbols = concatenate ( symbols , typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ) ;
2319
2352
Debug . assertEachIsDefined ( symbols , "getSymbolsInScope() should all be defined" ) ;
2320
- for ( const symbol of symbols ) {
2353
+ for ( let i = 0 ; i < symbols . length ; i ++ ) {
2354
+ const symbol = symbols [ i ] ;
2321
2355
if ( ! typeChecker . isArgumentsSymbol ( symbol ) &&
2322
2356
! some ( symbol . declarations , d => d . getSourceFile ( ) === sourceFile ) ) {
2323
2357
symbolToSortTextIdMap [ getSymbolId ( symbol ) ] = SortTextId . GlobalsOrKeywords ;
2324
2358
}
2359
+ if ( typeOnlyAliasNeedsPromotion && ! ( symbol . flags & SymbolFlags . Value ) ) {
2360
+ const typeOnlyAliasDeclaration = symbol . declarations && find ( symbol . declarations , isTypeOnlyImportOrExportDeclaration ) ;
2361
+ if ( typeOnlyAliasDeclaration ) {
2362
+ const origin : SymbolOriginInfoTypeOnlyAlias = { kind : SymbolOriginInfoKind . TypeOnlyAlias , declaration : typeOnlyAliasDeclaration } ;
2363
+ symbolToOriginInfoMap [ i ] = origin ;
2364
+ }
2365
+ }
2325
2366
}
2326
2367
2327
2368
// Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions`
@@ -3905,10 +3946,15 @@ namespace ts.Completions {
3905
3946
3906
3947
/** True if symbol is a type or a module containing at least one type. */
3907
3948
function symbolCanBeReferencedAtTypeLocation ( symbol : Symbol , checker : TypeChecker , seenModules = new Map < SymbolId , true > ( ) ) : boolean {
3908
- const sym = skipAlias ( symbol . exportSymbol || symbol , checker ) ;
3909
- return ! ! ( sym . flags & SymbolFlags . Type ) || checker . isUnknownSymbol ( sym ) ||
3910
- ! ! ( sym . flags & SymbolFlags . Module ) && addToSeen ( seenModules , getSymbolId ( sym ) ) &&
3911
- checker . getExportsOfModule ( sym ) . some ( e => symbolCanBeReferencedAtTypeLocation ( e , checker , seenModules ) ) ;
3949
+ // Since an alias can be merged with a local declaration, we need to test both the alias and its target.
3950
+ // This code used to just test the result of `skipAlias`, but that would ignore any locally introduced meanings.
3951
+ return nonAliasCanBeReferencedAtTypeLocation ( symbol ) || nonAliasCanBeReferencedAtTypeLocation ( skipAlias ( symbol . exportSymbol || symbol , checker ) ) ;
3952
+
3953
+ function nonAliasCanBeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
3954
+ return ! ! ( symbol . flags & SymbolFlags . Type ) || checker . isUnknownSymbol ( symbol ) ||
3955
+ ! ! ( symbol . flags & SymbolFlags . Module ) && addToSeen ( seenModules , getSymbolId ( symbol ) ) &&
3956
+ checker . getExportsOfModule ( symbol ) . some ( e => symbolCanBeReferencedAtTypeLocation ( e , checker , seenModules ) ) ;
3957
+ }
3912
3958
}
3913
3959
3914
3960
function isDeprecated ( symbol : Symbol , checker : TypeChecker ) {
0 commit comments