@@ -86,11 +86,11 @@ namespace ts.Completions {
8686 case StringLiteralCompletionKind . Properties : {
8787 const entries : CompletionEntry [ ] = [ ] ;
8888 getCompletionEntriesFromSymbols ( completion . symbols , entries , sourceFile , sourceFile , checker , ScriptTarget . ESNext , log , CompletionKind . String , preferences ) ; // Target will not be used, so arbitrary
89- return { isGlobalCompletion : false , isMemberCompletion : true , isNewIdentifierLocation : true , entries } ;
89+ return { isGlobalCompletion : false , isMemberCompletion : true , isNewIdentifierLocation : completion . hasIndexSignature , entries } ;
9090 }
9191 case StringLiteralCompletionKind . Types : {
9292 const entries = completion . types . map ( type => ( { name : type . value , kindModifiers : ScriptElementKindModifier . none , kind : ScriptElementKind . typeElement , sortText : "0" } ) ) ;
93- return { isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation : true , entries } ;
93+ return { isGlobalCompletion : false , isMemberCompletion : false , isNewIdentifierLocation : false , entries } ;
9494 }
9595 default :
9696 return Debug . assertNever ( completion ) ;
@@ -360,9 +360,14 @@ namespace ts.Completions {
360360 }
361361
362362 const enum StringLiteralCompletionKind { Paths , Properties , Types }
363+ interface StringLiteralCompletionsFromProperties {
364+ readonly kind : StringLiteralCompletionKind . Properties ;
365+ readonly symbols : ReadonlyArray < Symbol > ;
366+ readonly hasIndexSignature : boolean ;
367+ }
363368 type StringLiteralCompletion =
364369 | { readonly kind : StringLiteralCompletionKind . Paths , readonly paths : ReadonlyArray < PathCompletions . PathCompletion > }
365- | { readonly kind : StringLiteralCompletionKind . Properties , readonly symbols : ReadonlyArray < Symbol > }
370+ | StringLiteralCompletionsFromProperties
366371 | { readonly kind : StringLiteralCompletionKind . Types , readonly types : ReadonlyArray < StringLiteralType > } ;
367372 function getStringLiteralCompletionEntries ( sourceFile : SourceFile , node : StringLiteralLike , position : number , typeChecker : TypeChecker , compilerOptions : CompilerOptions , host : LanguageServiceHost ) : StringLiteralCompletion | undefined {
368373 switch ( node . parent . kind ) {
@@ -377,7 +382,7 @@ namespace ts.Completions {
377382 // bar: string;
378383 // }
379384 // let x: Foo["/*completion position*/"]
380- return { kind : StringLiteralCompletionKind . Properties , symbols : typeChecker . getTypeFromTypeNode ( ( node . parent . parent as IndexedAccessTypeNode ) . objectType ) . getApparentProperties ( ) } ;
385+ return stringLiteralCompletionsFromProperties ( typeChecker . getTypeFromTypeNode ( ( node . parent . parent as IndexedAccessTypeNode ) . objectType ) ) ;
381386 default :
382387 return undefined ;
383388 }
@@ -396,8 +401,7 @@ namespace ts.Completions {
396401 // foo({
397402 // '/*completion position*/'
398403 // });
399- const type = typeChecker . getContextualType ( node . parent . parent ) ;
400- return { kind : StringLiteralCompletionKind . Properties , symbols : type && type . getApparentProperties ( ) } ;
404+ return stringLiteralCompletionsFromProperties ( typeChecker . getContextualType ( node . parent . parent ) ) ;
401405 }
402406 return fromContextualType ( ) ;
403407
@@ -410,7 +414,7 @@ namespace ts.Completions {
410414 // }
411415 // let a: A;
412416 // a['/*completion position*/']
413- return { kind : StringLiteralCompletionKind . Properties , symbols : typeChecker . getTypeAtLocation ( expression ) . getApparentProperties ( ) } ;
417+ return stringLiteralCompletionsFromProperties ( typeChecker . getTypeAtLocation ( expression ) ) ;
414418 }
415419 return undefined ;
416420 }
@@ -454,6 +458,10 @@ namespace ts.Completions {
454458 }
455459 }
456460
461+ function stringLiteralCompletionsFromProperties ( type : Type | undefined ) : StringLiteralCompletionsFromProperties | undefined {
462+ return type && { kind : StringLiteralCompletionKind . Properties , symbols : type . getApparentProperties ( ) , hasIndexSignature : hasIndexSignature ( type ) } ;
463+ }
464+
457465 function getStringLiteralTypes ( type : Type , typeChecker : TypeChecker , uniques = createMap < true > ( ) ) : ReadonlyArray < StringLiteralType > {
458466 if ( type && type . flags & TypeFlags . TypeParameter ) {
459467 type = type . getConstraint ( ) ;
@@ -1051,7 +1059,7 @@ namespace ts.Completions {
10511059 }
10521060
10531061 function addTypeProperties ( type : Type ) : void {
1054- isNewIdentifierLocation = ! ! type . getStringIndexType ( ) || ! ! type . getNumberIndexType ( ) ;
1062+ isNewIdentifierLocation = hasIndexSignature ( type ) ;
10551063
10561064 if ( isSourceFileJavaScript ( sourceFile ) ) {
10571065 // In javascript files, for union types, we don't just get the members that
@@ -1454,11 +1462,9 @@ namespace ts.Completions {
14541462 let existingMembers : ReadonlyArray < Declaration > ;
14551463
14561464 if ( objectLikeContainer . kind === SyntaxKind . ObjectLiteralExpression ) {
1457- // We are completing on contextual types, but may also include properties
1458- // other than those within the declared type.
1459- isNewIdentifierLocation = true ;
14601465 const typeForObject = typeChecker . getContextualType ( objectLikeContainer ) ;
14611466 if ( ! typeForObject ) return GlobalsSearch . Fail ;
1467+ isNewIdentifierLocation = hasIndexSignature ( typeForObject ) ;
14621468 typeMembers = getPropertiesForCompletion ( typeForObject , typeChecker , /*isForAccess*/ false ) ;
14631469 existingMembers = objectLikeContainer . properties ;
14641470 }
@@ -2247,4 +2253,8 @@ namespace ts.Completions {
22472253 function isFromObjectTypeDeclaration ( node : Node ) : boolean {
22482254 return node . parent && ( isClassElement ( node . parent ) || isTypeElement ( node . parent ) ) && isObjectTypeDeclaration ( node . parent . parent ) ;
22492255 }
2256+
2257+ function hasIndexSignature ( type : Type ) : boolean {
2258+ return ! ! type . getStringIndexType ( ) || ! ! type . getNumberIndexType ( ) ;
2259+ }
22502260}
0 commit comments