diff --git a/src/services/completions.ts b/src/services/completions.ts index f5f9824b0ad4e..41b8a8a1b3bc2 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -3032,16 +3032,9 @@ namespace ts.Completions { ? checker.getUnionType([contextualType, completionsType!]) : contextualType; - const properties = type.isUnion() - ? checker.getAllPossiblePropertiesOfTypes(type.types.filter(memberType => - // If we're providing completions for an object literal, skip primitive, array-like, or callable types since those shouldn't be implemented by object literals. - !(memberType.flags & TypeFlags.Primitive || - checker.isArrayLikeType(memberType) || - typeHasCallOrConstructSignatures(memberType, checker) || - checker.isTypeInvalidDueToUnionDiscriminant(memberType, obj)))) - : type.getApparentProperties(); - - return hasCompletionsType ? properties.filter(hasDeclarationOtherThanSelf) : properties; + const properties = getApparentProperties(type, obj, checker); + return type.isClass() && containsNonPublicProperties(properties) ? [] : + hasCompletionsType ? filter(properties, hasDeclarationOtherThanSelf) : properties; // Filter out members whose only declaration is the object literal itself to avoid // self-fulfilling completions like: @@ -3053,6 +3046,20 @@ namespace ts.Completions { } } + function getApparentProperties(type: Type, node: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker) { + if (!type.isUnion()) return type.getApparentProperties(); + return checker.getAllPossiblePropertiesOfTypes(filter(type.types, memberType => + !(memberType.flags & TypeFlags.Primitive + || checker.isArrayLikeType(memberType) + || checker.isTypeInvalidDueToUnionDiscriminant(memberType, node) + || typeHasCallOrConstructSignatures(memberType, checker) + || memberType.isClass() && containsNonPublicProperties(memberType.getApparentProperties())))); + } + + function containsNonPublicProperties(props: Symbol[]) { + return some(props, p => !!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier)); + } + /** * Gets all properties on a type, but if that type is a union of several types, * excludes array-like types or callable/constructable types. diff --git a/tests/cases/fourslash/completionInsideObjectLiteralExpressionWithInstantiatedClassType.ts b/tests/cases/fourslash/completionInsideObjectLiteralExpressionWithInstantiatedClassType.ts new file mode 100644 index 0000000000000..beda6f3b9869a --- /dev/null +++ b/tests/cases/fourslash/completionInsideObjectLiteralExpressionWithInstantiatedClassType.ts @@ -0,0 +1,38 @@ +/// + +////class C1 { +//// public a: string; +//// protected b: string; +//// private c: string; +//// +//// constructor(a: string, b = "", c = "") { +//// this.a = a; +//// this.b = b; +//// this.c = c; +//// } +////} +////class C2 { +//// public a: string; +//// constructor(a: string) { +//// this.a = a; +//// } +////} +////function f1(foo: C1 | C2 | { d: number }) {} +////f1({ /*1*/ }); + +////function f2(foo: C1 | C2) {} +////f2({ /*2*/ }); +//// +////function f3(foo: C2) {} +////f3({ /*3*/ }); + +verify.completions({ + marker: "1", + exact: ["a", "d"], +}, { + marker: "2", + exact: ["a"] +}, { + marker: "3", + exact: ["a"] +});