Skip to content

Commit 32a50c3

Browse files
committed
Suggest completions within string literals in type arguments
1 parent c086eb4 commit 32a50c3

File tree

5 files changed

+76
-1
lines changed

5 files changed

+76
-1
lines changed

src/services/completions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5768,7 +5768,8 @@ function tryGetTypeLiteralNode(node: Node): TypeLiteralNode | undefined {
57685768
return undefined;
57695769
}
57705770

5771-
function getConstraintOfTypeArgumentProperty(node: Node, checker: TypeChecker): Type | undefined {
5771+
/** @internal */
5772+
export function getConstraintOfTypeArgumentProperty(node: Node, checker: TypeChecker): Type | undefined {
57725773
if (!node) return undefined;
57735774

57745775
if (isTypeNode(node)) {

src/services/stringCompletions.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
getCompletionEntriesFromSymbols,
66
getDefaultCommitCharacters,
77
getPropertiesForObjectExpression,
8+
getConstraintOfTypeArgumentProperty,
89
Log,
910
SortText,
1011
} from "./_namespaces/ts.Completions.js";
@@ -509,7 +510,12 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
509510

510511
function fromUnionableLiteralType(grandParent: Node): StringLiteralCompletionsFromTypes | StringLiteralCompletionsFromProperties | undefined {
511512
switch (grandParent.kind) {
513+
case SyntaxKind.CallExpression:
512514
case SyntaxKind.ExpressionWithTypeArguments:
515+
case SyntaxKind.JsxOpeningElement:
516+
case SyntaxKind.JsxSelfClosingElement:
517+
case SyntaxKind.NewExpression:
518+
case SyntaxKind.TaggedTemplateExpression:
513519
case SyntaxKind.TypeReference: {
514520
const typeArgument = findAncestor(parent, n => n.parent === grandParent) as LiteralTypeNode;
515521
if (typeArgument) {
@@ -529,6 +535,8 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
529535
return undefined;
530536
}
531537
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode(objectType));
538+
case SyntaxKind.PropertySignature:
539+
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(getConstraintOfTypeArgumentProperty(grandParent, typeChecker)), isNewIdentifier: false };
532540
case SyntaxKind.UnionType: {
533541
const result = fromUnionableLiteralType(walkUpParentheses(grandParent.parent));
534542
if (!result) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////class Foo<T extends { x: 'one' | 'two' }> {}
4+
////function foo<T extends { x: 'one' | 'two' }>() {}
5+
////declare function tag<T extends { x: 'one' | 'two' }>(x: TemplateStringsArray): void;
6+
////declare function decorator<T extends { x: 'one' | 'two' }>(...args: unknown[]): never
7+
////
8+
////type A = Foo<{ x: '/*0*/' }>;
9+
////new Foo<{ x: '/*1*/' }>();
10+
////foo<{ x: '/*2*/' }>();
11+
////foo<{ x: '/*3*/' }>;
12+
////Foo<{ x: '/*4*/' }>;
13+
////tag<{ x: '/*5*/' }>``;
14+
////class { @decorator<{ x: '/*6*/' }>; method() {} }
15+
16+
verify.completions(
17+
{ marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: false },
18+
{ marker: "1", unsorted: ["one", "two"], isNewIdentifierLocation: false },
19+
{ marker: "2", unsorted: ["one", "two"], isNewIdentifierLocation: false },
20+
{ marker: "3", unsorted: ["one", "two"], isNewIdentifierLocation: false },
21+
{ marker: "4", unsorted: ["one", "two"], isNewIdentifierLocation: false },
22+
{ marker: "5", unsorted: ["one", "two"], isNewIdentifierLocation: false },
23+
{ marker: "6", unsorted: ["one", "two"], isNewIdentifierLocation: false },
24+
);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////class Foo<T extends 'one' | 'two'> {}
4+
////function foo<T extends 'one' | 'two'>() {}
5+
////declare function tag<T extends 'one' | 'two'>(x: TemplateStringsArray): void;
6+
////declare function decorator<T extends 'one' | 'two'>(...args: unknown[]): never
7+
////
8+
////type A = Foo<'/*0*/'>;
9+
////new Foo<'/*1*/'>();
10+
////foo<'/*2*/'>();
11+
////foo<'/*3*/'>;
12+
////Foo<'/*4*/'>;
13+
////tag<'/*5*/'>``;
14+
////class { @decorator<'/*6*/'>; method() {} }
15+
16+
verify.completions(
17+
{ marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: false },
18+
{ marker: "1", unsorted: ["one", "two"], isNewIdentifierLocation: false },
19+
{ marker: "2", unsorted: ["one", "two"], isNewIdentifierLocation: false },
20+
{ marker: "3", unsorted: ["one", "two"], isNewIdentifierLocation: false },
21+
{ marker: "4", unsorted: ["one", "two"], isNewIdentifierLocation: false },
22+
{ marker: "5", unsorted: ["one", "two"], isNewIdentifierLocation: false },
23+
{ marker: "6", unsorted: ["one", "two"], isNewIdentifierLocation: false },
24+
);
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+
// @jsx: preserve
4+
// @filename: a.tsx
5+
////const Component1 = <T extends { x: 'one' | 'two' }>() => <></>;
6+
////const Component2 = <T extends 'one' | 'two'>() => <></>;
7+
////
8+
////<Component1<{ x: '/*0*/' }>></Component>;
9+
////<Component1<{ x: '/*1*/' }>/>;
10+
////<Component2<'/*2*/'>></Component>;
11+
////<Component2<'/*3*/'>/>;
12+
13+
verify.completions(
14+
{ marker: "0", unsorted: ["one", "two"], isNewIdentifierLocation: false },
15+
{ marker: "1", unsorted: ["one", "two"], isNewIdentifierLocation: false },
16+
{ marker: "2", unsorted: ["one", "two"], isNewIdentifierLocation: false },
17+
{ marker: "3", unsorted: ["one", "two"], isNewIdentifierLocation: false },
18+
);

0 commit comments

Comments
 (0)