@@ -107,33 +107,12 @@ namespace ts.Completions.StringCompletions {
107107 readonly isNewIdentifier : boolean ;
108108 }
109109 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 {
111111 const { parent } = node ;
112112 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+ }
137116 case SyntaxKind . PropertyAssignment :
138117 if ( isObjectLiteralExpression ( parent . parent ) && ( < PropertyAssignment > parent ) . name === node ) {
139118 // Get quoted name of properties of the object literal expression
@@ -179,15 +158,20 @@ namespace ts.Completions.StringCompletions {
179158
180159 case SyntaxKind . ImportDeclaration :
181160 case SyntaxKind . ExportDeclaration :
182- case SyntaxKind . ExternalModuleReference :
161+ case SyntaxKind . ExternalModuleReference : {
183162 // Get all known external module names or complete a path to a module
184163 // i.e. import * as ns from "/*completion position*/";
185164 // var y = import("/*completion position*/");
186165 // import x = require("/*completion position*/");
187166 // var y = require("/*completion position*/");
188167 // 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 ) ;
191175 default :
192176 return fromContextualType ( ) ;
193177 }
@@ -199,6 +183,45 @@ namespace ts.Completions.StringCompletions {
199183 }
200184 }
201185
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+
202225 function getAlreadyUsedTypesInStringLiteralUnion ( union : UnionTypeNode , current : LiteralTypeNode ) : readonly string [ ] {
203226 return mapDefined ( union . types , type =>
204227 type !== current && isLiteralTypeNode ( type ) && isStringLiteral ( type . literal ) ? type . literal . text : undefined ) ;
0 commit comments