diff --git a/src/services/completions.ts b/src/services/completions.ts
index 40f3cac68c95c..51a296aeafb80 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -1086,6 +1086,7 @@ namespace ts.Completions {
const semanticStart = timestamp();
let completionKind = CompletionKind.None;
let isNewIdentifierLocation = false;
+ let isNonContextualObjectLiteral = false;
let keywordFilters = KeywordCompletionFilters.None;
// This also gets mutated in nested-functions after the return
let symbols: Symbol[] = [];
@@ -1471,6 +1472,8 @@ namespace ts.Completions {
}
function shouldOfferImportCompletions(): boolean {
+ // If current completion is for non-contextual Object literal shortahands, ignore auto-import symbols
+ if (isNonContextualObjectLiteral) return false;
// If not already a module, must have modules enabled.
if (!preferences.includeCompletionsForModuleExports) return false;
// If already using ES6 modules, OK to continue using them.
@@ -1892,13 +1895,29 @@ namespace ts.Completions {
if (objectLikeContainer.kind === SyntaxKind.ObjectLiteralExpression) {
const instantiatedType = tryGetObjectLiteralContextualType(objectLikeContainer, typeChecker);
+
+ // Check completions for Object property value shorthand
if (instantiatedType === undefined) {
- return GlobalsSearch.Fail;
+ if (objectLikeContainer.flags & NodeFlags.InWithStatement) {
+ return GlobalsSearch.Fail;
+ }
+ isNonContextualObjectLiteral = true;
+ return GlobalsSearch.Continue;
}
const completionsType = typeChecker.getContextualType(objectLikeContainer, ContextFlags.Completions);
- isNewIdentifierLocation = hasIndexSignature(completionsType || instantiatedType);
+ const hasStringIndexType = (completionsType || instantiatedType).getStringIndexType();
+ const hasNumberIndextype = (completionsType || instantiatedType).getNumberIndexType();
+ isNewIdentifierLocation = !!hasStringIndexType || !!hasNumberIndextype;
typeMembers = getPropertiesForObjectExpression(instantiatedType, completionsType, objectLikeContainer, typeChecker);
existingMembers = objectLikeContainer.properties;
+
+ if (typeMembers.length === 0) {
+ // Edge case: If NumberIndexType exists
+ if (!hasNumberIndextype) {
+ isNonContextualObjectLiteral = true;
+ return GlobalsSearch.Continue;
+ }
+ }
}
else {
Debug.assert(objectLikeContainer.kind === SyntaxKind.ObjectBindingPattern);
@@ -2312,6 +2331,7 @@ namespace ts.Completions {
}
return isDeclarationName(contextToken)
+ && !isShorthandPropertyAssignment(contextToken.parent)
&& !isJsxAttribute(contextToken.parent)
// Don't block completions if we're in `class C /**/`, because we're *past* the end of the identifier and might want to complete `extends`.
// If `contextToken !== previousToken`, this is `class C ex/**/`.
diff --git a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_destructuring.ts b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_destructuring.ts
index 27c7f9a4dae21..6cc77a3f61cf8 100644
--- a/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_destructuring.ts
+++ b/tests/cases/fourslash/completionListAtIdentifierDefinitionLocations_destructuring.ts
@@ -1,19 +1,27 @@
///
+// @Filename: a.ts
//// var [x/*variable1*/
+// @Filename: b.ts
//// var [x, y/*variable2*/
+// @Filename: c.ts
//// var [./*variable3*/
+// @Filename: d.ts
//// var [x, ...z/*variable4*/
+// @Filename: e.ts
//// var {x/*variable5*/
+// @Filename: f.ts
//// var {x, y/*variable6*/
+// @Filename: g.ts
//// function func1({ a/*parameter1*/
+// @Filename: h.ts
//// function func2({ a, b/*parameter2*/
-verify.completions({ marker: test.markers(), exact: undefined });
+verify.completions({ marker: test.markers(), exact: undefined });
\ No newline at end of file
diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral.ts
new file mode 100644
index 0000000000000..0f8f65e70ebd1
--- /dev/null
+++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral.ts
@@ -0,0 +1,66 @@
+///
+
+//// declare const foo: number;
+//// interface Empty {}
+//// interface Typed { typed: number; }
+
+//// declare function f1(obj): void;
+//// declare function f2(obj: any): void;
+//// declare function f3(obj: unknown): void;
+//// declare function f4(obj: object): void;
+//// declare function f5(obj: Record): void;
+//// declare function f6(obj: { [key: string]: number }): void;
+//// declare function f7(obj: T): void;
+//// declare function f8(obj: T): void;
+//// declare function f9(obj: T): void;
+//// declare function f10(obj: T): void;
+//// declare function f11 | {})>(obj: T): void;
+
+//// declare function f12(obj: Typed): void;
+//// declare function f13(obj: T): void;
+
+//// declare function f14(obj: { [key: string]: number, prop: number }): void;
+
+//// declare function f15(obj: Record): void;
+//// declare function f16(obj: { [key: number]: number }): void;
+
+//// f1({f/*1*/});
+//// f2({f/*2*/});
+//// f3({f/*3*/});
+//// f4({f/*4*/});
+//// f5({f/*5*/});
+//// f6({f/*6*/});
+//// f7({f/*7*/});
+//// f8({f/*8*/});
+//// f9({f/*9*/});
+//// f10({f/*10*/});
+//// f11({f/*11*/});
+
+//// f12({f/*12*/});
+//// f13({f/*13*/});
+
+//// f14({f/*14*/});
+
+//// f15({f/*15*/});
+//// f16({f/*16*/});
+
+const locals = [
+ ...(() => {
+ const symbols = [];
+ for (let i = 1; i <= 16; i ++) {
+ symbols.push(`f${i}`);
+ }
+ return symbols;
+ })(),
+ "foo"
+];
+verify.completions(
+ // Non-contextual, any, unknown, object, Record, [key: string]: .., Type parameter, etc..
+ { marker: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], exact: completion.globalsPlus(locals)},
+ // Has named property
+ { marker: ["12", "13"], exact: "typed"},
+ // Has both StringIndexType and named property
+ { marker: ["14"], exact: "prop", isNewIdentifierLocation: true},
+ // NumberIndexType
+ { marker: ["15", "16"], exact: [], isNewIdentifierLocation: true},
+);
diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral2.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral2.ts
new file mode 100644
index 0000000000000..ec54418c77935
--- /dev/null
+++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral2.ts
@@ -0,0 +1,17 @@
+///
+
+//// const foo = 1;
+//// const bar = 2;
+
+//// const obj1 = {
+//// foo b/*1*/
+//// };
+
+//// const obj2: any = {
+//// foo b/*2*/
+//// };
+
+verify.completions({
+ marker: test.markers(),
+ exact: completion.globalsPlus(["foo", "bar", "obj1", "obj2"]),
+});
diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral3.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral3.ts
new file mode 100644
index 0000000000000..0a6fad60b293e
--- /dev/null
+++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral3.ts
@@ -0,0 +1,11 @@
+///
+
+//// const foo = 1;
+//// const bar = 2;
+//// const obj = {
+//// foo b/*1*/
+
+verify.completions({
+ marker: ["1"],
+ exact: completion.globalsPlus(["foo", "bar", "obj"])
+});
diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral4.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral4.ts
new file mode 100644
index 0000000000000..35daa6185a3f1
--- /dev/null
+++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral4.ts
@@ -0,0 +1,11 @@
+///
+
+//// const foo = 1;
+//// const bar = 2;
+//// const obj: any = {
+//// foo b/*1*/
+
+verify.completions({
+ marker: ["1"],
+ exact: completion.globalsPlus(["foo", "bar", "obj"])
+});
diff --git a/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral5.ts b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral5.ts
new file mode 100644
index 0000000000000..74ded23477463
--- /dev/null
+++ b/tests/cases/fourslash/completionPropertyShorthandForObjectLiteral5.ts
@@ -0,0 +1,13 @@
+// @module: esnext
+
+// @Filename: /a.ts
+//// export const exportedConstant = 0;
+
+// @Filename: /b.ts
+//// const obj = { exp/**/
+
+verify.completions({
+ marker: "",
+ exact: completion.globalsPlus(["obj"]),
+ preferences: { includeCompletionsForModuleExports: true }
+});
\ No newline at end of file
diff --git a/tests/cases/fourslash/completionsGenericUnconstrained.ts b/tests/cases/fourslash/completionsGenericUnconstrained.ts
index 3865dc515618f..d18991830e7dd 100644
--- a/tests/cases/fourslash/completionsGenericUnconstrained.ts
+++ b/tests/cases/fourslash/completionsGenericUnconstrained.ts
@@ -10,5 +10,8 @@
verify.completions({
marker: "",
- exact: []
+ includes: [{
+ name: "Object",
+ sortText: completion.SortText.GlobalsOrKeywords
+ }]
});
diff --git a/tests/cases/fourslash/completionsSelfDeclaring2.ts b/tests/cases/fourslash/completionsSelfDeclaring2.ts
index ee313de90c0bf..7a46020a2c210 100644
--- a/tests/cases/fourslash/completionsSelfDeclaring2.ts
+++ b/tests/cases/fourslash/completionsSelfDeclaring2.ts
@@ -1,15 +1,15 @@
///
-////function f1(x: T) {}
-////f1({ abc/*1*/ });
-////
-////function f2(x: T) {}
-////f2({ x/*2*/ });
+//// function f1(x: T) {}
+//// f1({ abc/*1*/ });
+
+//// function f2(x: T) {}
+//// f2({ x/*2*/ });
verify.completions({
marker: "1",
- exact: []
+ exact: completion.globalsPlus(["f1", "f2"])
});
verify.completions({
diff --git a/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts b/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts
index e41ec0a99f44d..503758461489b 100644
--- a/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts
+++ b/tests/cases/fourslash/globalCompletionListInsideObjectLiterals.ts
@@ -28,7 +28,6 @@
// 5, 6: Literal member completion after member name with empty member expression.
const exact = ["p1", "p2", "p3", "p4", ...completion.globalsPlus(["ObjectLiterals"])];
verify.completions(
- { marker: ["1"], exact, isNewIdentifierLocation: true },
- { marker: ["2", "3", "5", "6"], exact },
- { marker: "4", exact: undefined },
+ { marker: ["1",], exact, isNewIdentifierLocation: true },
+ { marker: ["2", "3", "4", "5", "6"], exact }
);