@@ -20,7 +20,8 @@ namespace ts.Completions {
2020 None ,
2121 ClassElementKeywords , // Keywords at class keyword
2222 ConstructorParameterKeywords , // Keywords at constructor parameter
23- FunctionLikeBodyKeywords // Keywords at function like body
23+ FunctionLikeBodyKeywords , // Keywords at function like body
24+ TypeKeywords ,
2425 }
2526
2627 export function getCompletionsAtPosition (
@@ -565,7 +566,7 @@ namespace ts.Completions {
565566 }
566567 case "none" : {
567568 // Didn't find a symbol with this name. See if we can find a keyword instead.
568- if ( some ( getKeywordCompletions ( KeywordCompletionFilters . None ) , c => c . name === name ) ) {
569+ if ( allKeywordsCompletions ( ) . some ( c => c . name === name ) ) {
569570 return {
570571 name,
571572 kind : ScriptElementKind . keyword ,
@@ -1163,26 +1164,24 @@ namespace ts.Completions {
11631164 }
11641165
11651166 function filterGlobalCompletion ( symbols : Symbol [ ] ) : void {
1167+ const isTypeCompletion = insideJsDocTagTypeExpression || ! isContextTokenValueLocation ( contextToken ) && ( isPartOfTypeNode ( location ) || isContextTokenTypeLocation ( contextToken ) ) ;
1168+ if ( isTypeCompletion ) keywordFilters = KeywordCompletionFilters . TypeKeywords ;
1169+
11661170 filterMutate ( symbols , symbol => {
11671171 if ( ! isSourceFile ( location ) ) {
11681172 // export = /**/ here we want to get all meanings, so any symbol is ok
11691173 if ( isExportAssignment ( location . parent ) ) {
11701174 return true ;
11711175 }
11721176
1173- // This is an alias, follow what it aliases
1174- if ( symbol && symbol . flags & SymbolFlags . Alias ) {
1175- symbol = typeChecker . getAliasedSymbol ( symbol ) ;
1176- }
1177+ symbol = skipAlias ( symbol , typeChecker ) ;
11771178
11781179 // import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
11791180 if ( isInRightSideOfInternalImportEqualsDeclaration ( location ) ) {
11801181 return ! ! ( symbol . flags & SymbolFlags . Namespace ) ;
11811182 }
11821183
1183- if ( insideJsDocTagTypeExpression ||
1184- ( ! isContextTokenValueLocation ( contextToken ) &&
1185- ( isPartOfTypeNode ( location ) || isContextTokenTypeLocation ( contextToken ) ) ) ) {
1184+ if ( isTypeCompletion ) {
11861185 // Its a type, but you can reach it by namespace.type as well
11871186 return symbolCanBeReferencedAtTypeLocation ( symbol ) ;
11881187 }
@@ -1199,7 +1198,7 @@ namespace ts.Completions {
11991198 contextToken . parent . kind === SyntaxKind . TypeQuery ;
12001199 }
12011200
1202- function isContextTokenTypeLocation ( contextToken : Node ) {
1201+ function isContextTokenTypeLocation ( contextToken : Node ) : boolean {
12031202 if ( contextToken ) {
12041203 const parentKind = contextToken . parent . kind ;
12051204 switch ( contextToken . kind ) {
@@ -1217,6 +1216,7 @@ namespace ts.Completions {
12171216 return parentKind === SyntaxKind . AsExpression ;
12181217 }
12191218 }
1219+ return false ;
12201220 }
12211221
12221222 function symbolCanBeReferencedAtTypeLocation ( symbol : Symbol ) : boolean {
@@ -2130,50 +2130,40 @@ namespace ts.Completions {
21302130 }
21312131
21322132 // A cache of completion entries for keywords, these do not change between sessions
2133- const _keywordCompletions : CompletionEntry [ ] [ ] = [ ] ;
2134- function getKeywordCompletions ( keywordFilter : KeywordCompletionFilters ) : CompletionEntry [ ] {
2135- const completions = _keywordCompletions [ keywordFilter ] ;
2136- if ( completions ) {
2137- return completions ;
2138- }
2139- return _keywordCompletions [ keywordFilter ] = generateKeywordCompletions ( keywordFilter ) ;
2140-
2141- type FilterKeywordCompletions = ( entryName : string ) => boolean ;
2142- function generateKeywordCompletions ( keywordFilter : KeywordCompletionFilters ) : CompletionEntry [ ] {
2143- switch ( keywordFilter ) {
2144- case KeywordCompletionFilters . None :
2145- return getAllKeywordCompletions ( ) ;
2146- case KeywordCompletionFilters . ClassElementKeywords :
2147- return getFilteredKeywordCompletions ( isClassMemberCompletionKeywordText ) ;
2148- case KeywordCompletionFilters . ConstructorParameterKeywords :
2149- return getFilteredKeywordCompletions ( isConstructorParameterCompletionKeywordText ) ;
2150- case KeywordCompletionFilters . FunctionLikeBodyKeywords :
2151- return getFilteredKeywordCompletions ( isFunctionLikeBodyCompletionKeywordText ) ;
2152- default :
2153- Debug . assertNever ( keywordFilter ) ;
2154- }
2155- }
2156-
2157- function getAllKeywordCompletions ( ) {
2158- const allKeywordsCompletions : CompletionEntry [ ] = [ ] ;
2159- for ( let i = SyntaxKind . FirstKeyword ; i <= SyntaxKind . LastKeyword ; i ++ ) {
2133+ const _keywordCompletions : ReadonlyArray < CompletionEntry > [ ] = [ ] ;
2134+ const allKeywordsCompletions : ( ) => ReadonlyArray < CompletionEntry > = ts . memoize ( ( ) => {
2135+ const res : CompletionEntry [ ] = [ ] ;
2136+ for ( let i = SyntaxKind . FirstKeyword ; i <= SyntaxKind . LastKeyword ; i ++ ) {
2137+ res . push ( createKeywordCompletionEntry ( i ) ) ;
2138+ }
2139+ return res ;
2140+ } ) ;
2141+ function createKeywordCompletionEntry ( kind : SyntaxKind ) : CompletionEntry {
2142+ return {
2143+ name : tokenToString ( kind ) ,
2144+ kind : ScriptElementKind . keyword ,
2145+ kindModifiers : ScriptElementKindModifier . none ,
2146+ sortText : "0"
2147+ } ;
2148+ }
2149+ function getKeywordCompletions ( keywordFilter : KeywordCompletionFilters ) : ReadonlyArray < CompletionEntry > {
2150+ return _keywordCompletions [ keywordFilter ] || ( _keywordCompletions [ keywordFilter ] = allKeywordsCompletions ( ) . filter ( entry => isValidKeyword ( keywordFilter , stringToToken ( entry . name ) ) ) ) ;
2151+ }
2152+ function isValidKeyword ( keywordFilter : KeywordCompletionFilters , kind : SyntaxKind ) : boolean {
2153+ switch ( keywordFilter ) {
2154+ case KeywordCompletionFilters . None :
21602155 // "undefined" is a global variable, so don't need a keyword completion for it.
2161- if ( i === SyntaxKind . UndefinedKeyword ) continue ;
2162- allKeywordsCompletions . push ( {
2163- name : tokenToString ( i ) ,
2164- kind : ScriptElementKind . keyword ,
2165- kindModifiers : ScriptElementKindModifier . none ,
2166- sortText : "0"
2167- } ) ;
2168- }
2169- return allKeywordsCompletions ;
2170- }
2171-
2172- function getFilteredKeywordCompletions ( filterFn : FilterKeywordCompletions ) {
2173- return filter (
2174- getKeywordCompletions ( KeywordCompletionFilters . None ) ,
2175- entry => filterFn ( entry . name )
2176- ) ;
2156+ return kind !== SyntaxKind . UndefinedKeyword ;
2157+ case KeywordCompletionFilters . ClassElementKeywords :
2158+ return isClassMemberCompletionKeyword ( kind ) ;
2159+ case KeywordCompletionFilters . ConstructorParameterKeywords :
2160+ return isConstructorParameterCompletionKeyword ( kind ) ;
2161+ case KeywordCompletionFilters . FunctionLikeBodyKeywords :
2162+ return isFunctionLikeBodyCompletionKeyword ( kind ) ;
2163+ case KeywordCompletionFilters . TypeKeywords :
2164+ return kind === SyntaxKind . KeyOfKeyword || kind === SyntaxKind . UniqueKeyword || ts . isTypeKeyword ( kind ) ;
2165+ default :
2166+ Debug . assertNever ( keywordFilter ) ;
21772167 }
21782168 }
21792169
@@ -2227,10 +2217,6 @@ namespace ts.Completions {
22272217 return true ;
22282218 }
22292219
2230- function isFunctionLikeBodyCompletionKeywordText ( text : string ) {
2231- return isFunctionLikeBodyCompletionKeyword ( stringToToken ( text ) ) ;
2232- }
2233-
22342220 function isEqualityOperatorKind ( kind : ts . SyntaxKind ) : kind is EqualityOperator {
22352221 switch ( kind ) {
22362222 case ts . SyntaxKind . EqualsEqualsEqualsToken :
0 commit comments