@@ -390,29 +390,34 @@ namespace ts.Completions {
390
390
}
391
391
type StringLiteralCompletion = { readonly kind : StringLiteralCompletionKind . Paths , readonly paths : ReadonlyArray < PathCompletions . PathCompletion > } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes ;
392
392
function getStringLiteralCompletionEntries ( sourceFile : SourceFile , node : StringLiteralLike , position : number , typeChecker : TypeChecker , compilerOptions : CompilerOptions , host : LanguageServiceHost ) : StringLiteralCompletion | undefined {
393
- switch ( node . parent . kind ) {
393
+ const { parent } = node ;
394
+ switch ( parent . kind ) {
394
395
case SyntaxKind . LiteralType :
395
- switch ( node . parent . parent . kind ) {
396
+ switch ( parent . parent . kind ) {
396
397
case SyntaxKind . TypeReference :
397
- return { kind : StringLiteralCompletionKind . Types , types : getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( node . parent as LiteralTypeNode ) ) , isNewIdentifier : false } ;
398
+ return { kind : StringLiteralCompletionKind . Types , types : getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( parent as LiteralTypeNode ) ) , isNewIdentifier : false } ;
398
399
case SyntaxKind . IndexedAccessType :
399
400
// Get all apparent property names
400
401
// i.e. interface Foo {
401
402
// foo: string;
402
403
// bar: string;
403
404
// }
404
405
// let x: Foo["/*completion position*/"]
405
- return stringLiteralCompletionsFromProperties ( typeChecker . getTypeFromTypeNode ( ( node . parent . parent as IndexedAccessTypeNode ) . objectType ) ) ;
406
+ return stringLiteralCompletionsFromProperties ( typeChecker . getTypeFromTypeNode ( ( parent . parent as IndexedAccessTypeNode ) . objectType ) ) ;
406
407
case SyntaxKind . ImportType :
407
408
return { kind : StringLiteralCompletionKind . Paths , paths : PathCompletions . getStringLiteralCompletionsFromModuleNames ( sourceFile , node , compilerOptions , host , typeChecker ) } ;
408
- case SyntaxKind . UnionType :
409
- return isTypeReferenceNode ( node . parent . parent . parent ) ? { kind : StringLiteralCompletionKind . Types , types : getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( node . parent . parent as UnionTypeNode ) ) , isNewIdentifier : false } : undefined ;
409
+ case SyntaxKind . UnionType : {
410
+ if ( ! isTypeReferenceNode ( parent . parent . parent ) ) return undefined ;
411
+ const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion ( parent . parent as UnionTypeNode , parent as LiteralTypeNode ) ;
412
+ const types = getStringLiteralTypes ( typeChecker . getTypeArgumentConstraint ( parent . parent as UnionTypeNode ) ) . filter ( t => ! contains ( alreadyUsedTypes , t . value ) ) ;
413
+ return { kind : StringLiteralCompletionKind . Types , types, isNewIdentifier : false } ;
414
+ }
410
415
default :
411
416
return undefined ;
412
417
}
413
418
414
419
case SyntaxKind . PropertyAssignment :
415
- if ( isObjectLiteralExpression ( node . parent . parent ) && ( < PropertyAssignment > node . parent ) . name === node ) {
420
+ if ( isObjectLiteralExpression ( parent . parent ) && ( < PropertyAssignment > parent ) . name === node ) {
416
421
// Get quoted name of properties of the object literal expression
417
422
// i.e. interface ConfigFiles {
418
423
// 'jspm:dev': string
@@ -425,12 +430,12 @@ namespace ts.Completions {
425
430
// foo({
426
431
// '/*completion position*/'
427
432
// });
428
- return stringLiteralCompletionsFromProperties ( typeChecker . getContextualType ( node . parent . parent ) ) ;
433
+ return stringLiteralCompletionsFromProperties ( typeChecker . getContextualType ( parent . parent ) ) ;
429
434
}
430
435
return fromContextualType ( ) ;
431
436
432
437
case SyntaxKind . ElementAccessExpression : {
433
- const { expression, argumentExpression } = node . parent as ElementAccessExpression ;
438
+ const { expression, argumentExpression } = parent as ElementAccessExpression ;
434
439
if ( node === argumentExpression ) {
435
440
// Get all names of properties on the expression
436
441
// i.e. interface A {
@@ -445,7 +450,7 @@ namespace ts.Completions {
445
450
446
451
case SyntaxKind . CallExpression :
447
452
case SyntaxKind . NewExpression :
448
- if ( ! isRequireCall ( node . parent , /*checkArgumentIsStringLiteralLike*/ false ) && ! isImportCall ( node . parent ) ) {
453
+ if ( ! isRequireCall ( parent , /*checkArgumentIsStringLiteralLike*/ false ) && ! isImportCall ( parent ) ) {
449
454
const argumentInfo = SignatureHelp . getArgumentInfoForCompletions ( node , position , sourceFile ) ;
450
455
// Get string literal completions from specialized signatures of the target
451
456
// i.e. declare function f(a: 'A');
@@ -476,6 +481,11 @@ namespace ts.Completions {
476
481
}
477
482
}
478
483
484
+ function getAlreadyUsedTypesInStringLiteralUnion ( union : UnionTypeNode , current : LiteralTypeNode ) : ReadonlyArray < string > {
485
+ return mapDefined ( union . types , type =>
486
+ type !== current && isLiteralTypeNode ( type ) && isStringLiteral ( type . literal ) ? type . literal . text : undefined ) ;
487
+ }
488
+
479
489
function getStringLiteralCompletionsFromSignature ( argumentInfo : SignatureHelp . ArgumentInfoForCompletions , checker : TypeChecker ) : StringLiteralCompletionsFromTypes {
480
490
let isNewIdentifier = false ;
481
491
0 commit comments