Skip to content

Commit c086eb4

Browse files
committed
Suggest completions of property values in type arguments
1 parent 65296fe commit c086eb4

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed

src/services/completions.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3625,17 +3625,20 @@ function getCompletionData(
36253625
}
36263626

36273627
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
3628-
const contextualType = previousToken && getContextualType(previousToken, position, sourceFile, typeChecker);
3628+
const contextualTypeOrConstraint = previousToken && (
3629+
getContextualType(previousToken, position, sourceFile, typeChecker) ??
3630+
getConstraintOfTypeArgumentProperty(previousToken, typeChecker)
3631+
);
36293632

36303633
// exclude literal suggestions after <input type="text" [||] /> (#51667) and after closing quote (#52675)
36313634
// for strings getStringLiteralCompletions handles completions
36323635
const isLiteralExpected = !tryCast(previousToken, isStringLiteralLike) && !isJsxIdentifierExpected;
36333636
const literals = !isLiteralExpected ? [] : mapDefined(
3634-
contextualType && (contextualType.isUnion() ? contextualType.types : [contextualType]),
3637+
contextualTypeOrConstraint && (contextualTypeOrConstraint.isUnion() ? contextualTypeOrConstraint.types : [contextualTypeOrConstraint]),
36353638
t => t.isLiteral() && !(t.flags & TypeFlags.EnumLiteral) ? t.value : undefined,
36363639
);
36373640

3638-
const recommendedCompletion = previousToken && contextualType && getRecommendedCompletion(previousToken, contextualType, typeChecker);
3641+
const recommendedCompletion = previousToken && contextualTypeOrConstraint && getRecommendedCompletion(previousToken, contextualTypeOrConstraint, typeChecker);
36393642
return {
36403643
kind: CompletionDataKind.Data,
36413644
symbols,
@@ -5779,6 +5782,13 @@ function getConstraintOfTypeArgumentProperty(node: Node, checker: TypeChecker):
57795782
switch (node.kind) {
57805783
case SyntaxKind.PropertySignature:
57815784
return checker.getTypeOfPropertyOfContextualType(t, (node as PropertySignature).symbol.escapedName);
5785+
case SyntaxKind.ColonToken:
5786+
if (node.parent.kind === SyntaxKind.PropertySignature) {
5787+
// The cursor is at a property value location like `Foo<{ x: | }`.
5788+
// `t` already refers to the appropriate property type.
5789+
return t;
5790+
}
5791+
break;
57825792
case SyntaxKind.IntersectionType:
57835793
case SyntaxKind.TypeLiteral:
57845794
case SyntaxKind.UnionType:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////class Foo<T extends { x: 'one' | 2 }> {}
4+
////function foo<T extends { x: 'one' | 2 }>() {}
5+
////
6+
////type A = Foo<{ x: /*0*/ }>;
7+
////new Foo<{ x: /*1*/ }>();
8+
////foo<{ x: /*2*/ }>();
9+
////foo<{ x: /*3*/ }>;
10+
////Foo<{ x: /*4*/ }>;
11+
12+
verify.completions(
13+
{ marker: "0", includes: ['"one"', '2'], isNewIdentifierLocation: false },
14+
{ marker: "1", includes: ['"one"', '2'], isNewIdentifierLocation: false },
15+
{ marker: "2", includes: ['"one"', '2'], isNewIdentifierLocation: false },
16+
{ marker: "3", includes: ['"one"', '2'], isNewIdentifierLocation: false },
17+
{ marker: "4", includes: ['"one"', '2'], isNewIdentifierLocation: false },
18+
);

0 commit comments

Comments
 (0)