Skip to content

Commit 1581636

Browse files
committed
feat(44888): omit completions in an object expression with an instantiated class type
1 parent 40ec839 commit 1581636

File tree

2 files changed

+54
-8
lines changed

2 files changed

+54
-8
lines changed

src/services/completions.ts

+16-8
Original file line numberDiff line numberDiff line change
@@ -2157,7 +2157,7 @@ namespace ts.Completions {
21572157
const hasStringIndexType = (completionsType || instantiatedType).getStringIndexType();
21582158
const hasNumberIndextype = (completionsType || instantiatedType).getNumberIndexType();
21592159
isNewIdentifierLocation = !!hasStringIndexType || !!hasNumberIndextype;
2160-
typeMembers = getPropertiesForObjectExpression(instantiatedType, completionsType, objectLikeContainer, typeChecker);
2160+
typeMembers = getPropertiesForObjectExpression(instantiatedType, completionsType, objectLikeContainer, typeChecker) || emptyArray;
21612161
existingMembers = objectLikeContainer.properties;
21622162

21632163
if (typeMembers.length === 0) {
@@ -3033,15 +3033,11 @@ namespace ts.Completions {
30333033
: contextualType;
30343034

30353035
const properties = type.isUnion()
3036-
? checker.getAllPossiblePropertiesOfTypes(type.types.filter(memberType =>
3037-
// 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.
3038-
!(memberType.flags & TypeFlags.Primitive ||
3039-
checker.isArrayLikeType(memberType) ||
3040-
typeHasCallOrConstructSignatures(memberType, checker) ||
3041-
checker.isTypeInvalidDueToUnionDiscriminant(memberType, obj))))
3036+
? checker.getAllPossiblePropertiesOfTypes(filter(type.types, memberType => isApparentType(memberType, obj, checker)))
30423037
: type.getApparentProperties();
30433038

3044-
return hasCompletionsType ? properties.filter(hasDeclarationOtherThanSelf) : properties;
3039+
return type.isClass() && containsHiddenProps(properties) ? [] :
3040+
hasCompletionsType ? filter(properties, hasDeclarationOtherThanSelf) : properties;
30453041

30463042
// Filter out members whose only declaration is the object literal itself to avoid
30473043
// self-fulfilling completions like:
@@ -3053,6 +3049,18 @@ namespace ts.Completions {
30533049
}
30543050
}
30553051

3052+
function isApparentType(type: Type, node: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker) {
3053+
return !(type.flags & TypeFlags.Primitive
3054+
|| checker.isArrayLikeType(type)
3055+
|| checker.isTypeInvalidDueToUnionDiscriminant(type, node)
3056+
|| typeHasCallOrConstructSignatures(type, checker)
3057+
|| type.isClass() && containsHiddenProps(type.getApparentProperties()));
3058+
}
3059+
3060+
function containsHiddenProps(props: Symbol[]) {
3061+
return some(props, p => !!(getDeclarationModifierFlagsFromSymbol(p) & ModifierFlags.NonPublicAccessibilityModifier));
3062+
}
3063+
30563064
/**
30573065
* Gets all properties on a type, but if that type is a union of several types,
30583066
* excludes array-like types or callable/constructable types.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
////class C1 {
4+
//// public a: string;
5+
//// protected b: string;
6+
//// private c: string;
7+
////
8+
//// constructor(a: string, b = "", c = "") {
9+
//// this.a = a;
10+
//// this.b = b;
11+
//// this.c = c;
12+
//// }
13+
////}
14+
////class C2 {
15+
//// public a: string;
16+
//// constructor(a: string) {
17+
//// this.a = a;
18+
//// }
19+
////}
20+
////function f1(foo: C1 | C2 | { d: number }) {}
21+
////f1({ /*1*/ });
22+
23+
////function f2(foo: C1 | C2) {}
24+
////f2({ /*2*/ });
25+
////
26+
////function f3(foo: C2) {}
27+
////f3({ /*3*/ });
28+
29+
verify.completions({
30+
marker: "1",
31+
exact: ["a", "d"],
32+
}, {
33+
marker: "2",
34+
exact: ["a"]
35+
}, {
36+
marker: "3",
37+
exact: ["a"]
38+
});

0 commit comments

Comments
 (0)