@@ -60,6 +60,8 @@ namespace ts.Completions {
6060 ThisProperty = "ThisProperty/" ,
6161 /** Auto-import that comes attached to a class member snippet */
6262 ClassMemberSnippet = "ClassMemberSnippet/" ,
63+ /** A type-only import that needs to be promoted in order to be used at the completion location */
64+ TypeOnlyAlias = "TypeOnlyAlias/" ,
6365 }
6466
6567 const enum SymbolOriginInfoKind {
@@ -69,6 +71,7 @@ namespace ts.Completions {
6971 Promise = 1 << 3 ,
7072 Nullable = 1 << 4 ,
7173 ResolvedExport = 1 << 5 ,
74+ TypeOnlyAlias = 1 << 6 ,
7275
7376 SymbolMemberNoExport = SymbolMember ,
7477 SymbolMemberExport = SymbolMember | Export ,
@@ -96,6 +99,10 @@ namespace ts.Completions {
9699 moduleSpecifier : string ;
97100 }
98101
102+ interface SymbolOriginInfoTypeOnlyAlias extends SymbolOriginInfo {
103+ declaration : TypeOnlyAliasDeclaration ;
104+ }
105+
99106 function originIsThisType ( origin : SymbolOriginInfo ) : boolean {
100107 return ! ! ( origin . kind & SymbolOriginInfoKind . ThisType ) ;
101108 }
@@ -128,6 +135,10 @@ namespace ts.Completions {
128135 return ! ! ( origin . kind & SymbolOriginInfoKind . Nullable ) ;
129136 }
130137
138+ function originIsTypeOnlyAlias ( origin : SymbolOriginInfo | undefined ) : origin is SymbolOriginInfoTypeOnlyAlias {
139+ return ! ! ( origin && origin . kind & SymbolOriginInfoKind . TypeOnlyAlias ) ;
140+ }
141+
131142 interface UniqueNameSet {
132143 add ( name : string ) : void ;
133144 has ( name : string ) : boolean ;
@@ -740,6 +751,10 @@ namespace ts.Completions {
740751 }
741752 }
742753
754+ if ( origin ?. kind === SymbolOriginInfoKind . TypeOnlyAlias ) {
755+ hasAction = true ;
756+ }
757+
743758 if ( preferences . includeCompletionsWithClassMemberSnippets &&
744759 preferences . includeCompletionsWithInsertText &&
745760 completionKind === CompletionKind . MemberLike &&
@@ -1168,6 +1183,9 @@ namespace ts.Completions {
11681183 if ( origin ?. kind === SymbolOriginInfoKind . ThisType ) {
11691184 return CompletionSource . ThisProperty ;
11701185 }
1186+ if ( origin ?. kind === SymbolOriginInfoKind . TypeOnlyAlias ) {
1187+ return CompletionSource . TypeOnlyAlias ;
1188+ }
11711189 }
11721190
11731191 export function getCompletionEntriesFromSymbols (
@@ -1245,7 +1263,7 @@ namespace ts.Completions {
12451263 }
12461264
12471265 /** 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 ( ) ) ) ;
12491267 uniques . set ( name , shouldShadowLaterSymbols ) ;
12501268 insertSorted ( entries , entry , compareCompletionEntries , /*allowDuplicates*/ true ) ;
12511269 }
@@ -1261,6 +1279,7 @@ namespace ts.Completions {
12611279 } ;
12621280
12631281 function shouldIncludeSymbol ( symbol : Symbol , symbolToSortTextIdMap : SymbolSortTextIdMap ) : boolean {
1282+ let allFlags = symbol . flags ;
12641283 if ( ! isSourceFile ( location ) ) {
12651284 // export = /**/ here we want to get all meanings, so any symbol is ok
12661285 if ( isExportAssignment ( location . parent ) ) {
@@ -1287,12 +1306,12 @@ namespace ts.Completions {
12871306 || symbolToSortTextIdMap [ getSymbolId ( symbolOrigin ) ] === SortTextId . LocationPriority ) ) {
12881307 return false ;
12891308 }
1290- // Continue with origin symbol
1291- symbol = symbolOrigin ;
1309+
1310+ allFlags |= getCombinedLocalAndExportSymbolFlags ( symbolOrigin ) ;
12921311
12931312 // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
12941313 if ( isInRightSideOfInternalImportEqualsDeclaration ( location ) ) {
1295- return ! ! ( symbol . flags & SymbolFlags . Namespace ) ;
1314+ return ! ! ( allFlags & SymbolFlags . Namespace ) ;
12961315 }
12971316
12981317 if ( isTypeOnlyLocation ) {
@@ -1302,7 +1321,7 @@ namespace ts.Completions {
13021321 }
13031322
13041323 // expressions are value space (which includes the value namespaces)
1305- return ! ! ( getCombinedLocalAndExportSymbolFlags ( symbol ) & SymbolFlags . Value ) ;
1324+ return ! ! ( allFlags & SymbolFlags . Value ) ;
13061325 }
13071326 }
13081327
@@ -1533,6 +1552,19 @@ namespace ts.Completions {
15331552 }
15341553 }
15351554
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+
15361568 if ( ! origin || ! ( originIsExport ( origin ) || originIsResolvedExport ( origin ) ) ) {
15371569 return { codeActions : undefined , sourceDisplay : undefined } ;
15381570 }
@@ -2314,14 +2346,23 @@ namespace ts.Completions {
23142346 isInSnippetScope = isSnippetScope ( scopeNode ) ;
23152347
23162348 const symbolMeanings = ( isTypeOnlyLocation ? SymbolFlags . None : SymbolFlags . Value ) | SymbolFlags . Type | SymbolFlags . Namespace | SymbolFlags . Alias ;
2349+ const typeOnlyAliasNeedsPromotion = previousToken && ! isValidTypeOnlyAliasUseSite ( previousToken ) ;
23172350
23182351 symbols = concatenate ( symbols , typeChecker . getSymbolsInScope ( scopeNode , symbolMeanings ) ) ;
23192352 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 ] ;
23212355 if ( ! typeChecker . isArgumentsSymbol ( symbol ) &&
23222356 ! some ( symbol . declarations , d => d . getSourceFile ( ) === sourceFile ) ) {
23232357 symbolToSortTextIdMap [ getSymbolId ( symbol ) ] = SortTextId . GlobalsOrKeywords ;
23242358 }
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+ }
23252366 }
23262367
23272368 // Need to insert 'this.' before properties of `this` type, so only do that if `includeInsertTextCompletions`
@@ -3905,10 +3946,15 @@ namespace ts.Completions {
39053946
39063947 /** True if symbol is a type or a module containing at least one type. */
39073948 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+ }
39123958 }
39133959
39143960 function isDeprecated ( symbol : Symbol , checker : TypeChecker ) {
0 commit comments