@@ -107,33 +107,12 @@ namespace ts.Completions.StringCompletions {
107
107
readonly isNewIdentifier : boolean ;
108
108
}
109
109
type StringLiteralCompletion = { readonly kind : StringLiteralCompletionKind . Paths , readonly paths : readonly PathCompletion [ ] } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes ;
110
- function getStringLiteralCompletionEntries ( sourceFile : SourceFile , node : StringLiteralLike , position : number , typeChecker : TypeChecker , compilerOptions : CompilerOptions , host : LanguageServiceHost ) : StringLiteralCompletion | undefined {
110
+ function getStringLiteralCompletionEntries ( sourceFile : SourceFile , node : StringLiteralLike | ParenthesizedExpression , position : number , typeChecker : TypeChecker , compilerOptions : CompilerOptions , host : LanguageServiceHost ) : StringLiteralCompletion | undefined {
111
111
const { parent } = node ;
112
112
switch ( parent . kind ) {
113
- case SyntaxKind . LiteralType :
114
- switch ( parent . parent . kind ) {
115
- case SyntaxKind . TypeReference :
116
- return { kind : StringLiteralCompletionKind . Types , types : getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( parent as LiteralTypeNode ) ) , isNewIdentifier : false } ;
117
- case SyntaxKind . IndexedAccessType :
118
- // Get all apparent property names
119
- // i.e. interface Foo {
120
- // foo: string;
121
- // bar: string;
122
- // }
123
- // let x: Foo["/*completion position*/"]
124
- return stringLiteralCompletionsFromProperties ( typeChecker . getTypeFromTypeNode ( ( parent . parent as IndexedAccessTypeNode ) . objectType ) ) ;
125
- case SyntaxKind . ImportType :
126
- return { kind : StringLiteralCompletionKind . Paths , paths : getStringLiteralCompletionsFromModuleNames ( sourceFile , node , compilerOptions , host , typeChecker ) } ;
127
- case SyntaxKind . UnionType : {
128
- if ( ! isTypeReferenceNode ( parent . parent . parent ) ) return undefined ;
129
- const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion ( parent . parent as UnionTypeNode , parent as LiteralTypeNode ) ;
130
- const types = getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( parent . parent as UnionTypeNode ) ) . filter ( t => ! contains ( alreadyUsedTypes , t . value ) ) ;
131
- return { kind : StringLiteralCompletionKind . Types , types, isNewIdentifier : false } ;
132
- }
133
- default :
134
- return undefined ;
135
- }
136
-
113
+ case SyntaxKind . LiteralType : {
114
+ return isStringLiteralLike ( node ) ? getCompletionEntriesFromStringLiteral ( sourceFile , node , typeChecker , compilerOptions , host ) : undefined ;
115
+ }
137
116
case SyntaxKind . PropertyAssignment :
138
117
if ( isObjectLiteralExpression ( parent . parent ) && ( < PropertyAssignment > parent ) . name === node ) {
139
118
// Get quoted name of properties of the object literal expression
@@ -179,15 +158,20 @@ namespace ts.Completions.StringCompletions {
179
158
180
159
case SyntaxKind . ImportDeclaration :
181
160
case SyntaxKind . ExportDeclaration :
182
- case SyntaxKind . ExternalModuleReference :
161
+ case SyntaxKind . ExternalModuleReference : {
183
162
// Get all known external module names or complete a path to a module
184
163
// i.e. import * as ns from "/*completion position*/";
185
164
// var y = import("/*completion position*/");
186
165
// import x = require("/*completion position*/");
187
166
// var y = require("/*completion position*/");
188
167
// export * from "/*completion position*/";
189
- return { kind : StringLiteralCompletionKind . Paths , paths : getStringLiteralCompletionsFromModuleNames ( sourceFile , node , compilerOptions , host , typeChecker ) } ;
190
-
168
+ if ( isStringLiteralLike ( node ) ) {
169
+ return { kind : StringLiteralCompletionKind . Paths , paths : getStringLiteralCompletionsFromModuleNames ( sourceFile , node , compilerOptions , host , typeChecker ) } ;
170
+ }
171
+ return undefined ;
172
+ }
173
+ case SyntaxKind . ParenthesizedExpression :
174
+ return getStringLiteralCompletionEntries ( sourceFile , parent as ParenthesizedExpression , position , typeChecker , compilerOptions , host ) ;
191
175
default :
192
176
return fromContextualType ( ) ;
193
177
}
@@ -199,6 +183,45 @@ namespace ts.Completions.StringCompletions {
199
183
}
200
184
}
201
185
186
+ function getCompletionEntriesFromStringLiteral ( sourceFile : SourceFile , node : StringLiteralLike | ParenthesizedTypeNode , typeChecker : TypeChecker , compilerOptions : CompilerOptions , host : LanguageServiceHost ) : StringLiteralCompletion | undefined {
187
+ const parent = node . parent ;
188
+ switch ( parent . parent . kind ) {
189
+ case SyntaxKind . TypeReference : {
190
+ if ( isLiteralTypeNode ( parent ) || isParenthesizedTypeNode ( parent ) ) {
191
+ return { kind : StringLiteralCompletionKind . Types , types : getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( parent ) ) , isNewIdentifier : false } ;
192
+ }
193
+ return undefined ;
194
+ }
195
+ case SyntaxKind . IndexedAccessType :
196
+ // Get all apparent property names
197
+ // i.e. interface Foo {
198
+ // foo: string;
199
+ // bar: string;
200
+ // }
201
+ // let x: Foo["/*completion position*/"]
202
+ return stringLiteralCompletionsFromProperties ( typeChecker . getTypeFromTypeNode ( ( parent . parent as IndexedAccessTypeNode ) . objectType ) ) ;
203
+ case SyntaxKind . ImportType : {
204
+ if ( isStringLiteralLike ( node ) ) {
205
+ return { kind : StringLiteralCompletionKind . Paths , paths : getStringLiteralCompletionsFromModuleNames ( sourceFile , node , compilerOptions , host , typeChecker ) } ;
206
+ }
207
+ return undefined ;
208
+ }
209
+ case SyntaxKind . UnionType : {
210
+ if ( ! isTypeReferenceNode ( parent . parent . parent ) ) {
211
+ return undefined ;
212
+ }
213
+ const unionType = parent . parent as UnionTypeNode ;
214
+ const alreadyUsedTypes = isLiteralTypeNode ( parent ) ? getAlreadyUsedTypesInStringLiteralUnion ( unionType , parent ) : [ ] ;
215
+ const types = getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( unionType ) ) . filter ( t => ! contains ( alreadyUsedTypes , t . value ) ) ;
216
+ return { kind : StringLiteralCompletionKind . Types , types, isNewIdentifier : false } ;
217
+ }
218
+ case SyntaxKind . ParenthesizedType :
219
+ return getCompletionEntriesFromStringLiteral ( sourceFile , parent as ParenthesizedTypeNode , typeChecker , compilerOptions , host ) ;
220
+ default :
221
+ return undefined ;
222
+ }
223
+ }
224
+
202
225
function getAlreadyUsedTypesInStringLiteralUnion ( union : UnionTypeNode , current : LiteralTypeNode ) : readonly string [ ] {
203
226
return mapDefined ( union . types , type =>
204
227
type !== current && isLiteralTypeNode ( type ) && isStringLiteral ( type . literal ) ? type . literal . text : undefined ) ;
0 commit comments