diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 7a1364c7a1f7b..c45bf8ad5eb21 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -230,9 +230,9 @@ namespace ts { const node = getParseTreeNode(nodeIn, isPropertyAccessOrQualifiedNameOrImportTypeNode); return !!node && isValidPropertyAccess(node, escapeLeadingUnderscores(propertyName)); }, - isValidPropertyAccessForCompletions: (nodeIn, type, property) => { + isValidPropertyAccessForCompletions: (nodeIn, type, property, skipMethodCheck) => { const node = getParseTreeNode(nodeIn, isPropertyAccessExpression); - return !!node && isValidPropertyAccessForCompletions(node, type, property); + return !!node && isValidPropertyAccessForCompletions(node, type, property, skipMethodCheck); }, getSignatureFromDeclaration: declarationIn => { const declaration = getParseTreeNode(declarationIn, isFunctionLike); @@ -19083,9 +19083,9 @@ namespace ts { } } - function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol): boolean { + function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol, skipMethodCheck: boolean): boolean { return isValidPropertyAccessWithType(node, node.kind !== SyntaxKind.ImportType && node.expression.kind === SyntaxKind.SuperKeyword, property.escapedName, type) - && (!(property.flags & SymbolFlags.Method) || isValidMethodAccess(property, type)); + && (!(property.flags & SymbolFlags.Method) || (skipMethodCheck || isValidMethodAccess(property, type))); } function isValidMethodAccess(method: Symbol, actualThisType: Type): boolean { const propType = getTypeOfPropertyOfType(actualThisType, method.escapedName)!; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 495465f70326c..dcd16a5cc628e 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3103,7 +3103,7 @@ namespace ts { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: string): boolean; /** Exclude accesses to private properties or methods with a `this` parameter that `type` doesn't satisfy. */ - /* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol): boolean; + /* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol, skipMethodCheck: boolean): boolean; /** Follow all aliases to get the original symbol. */ getAliasedSymbol(symbol: Symbol): Symbol; /** Follow a *single* alias to get the immediately aliased symbol. */ diff --git a/src/services/completions.ts b/src/services/completions.ts index 878b4bcd130b3..68463148c978e 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -912,8 +912,9 @@ namespace ts.Completions { symbols.push(...getPropertiesForCompletion(type, typeChecker)); } else { - for (const symbol of type.getApparentProperties()) { - if (typeChecker.isValidPropertyAccessForCompletions(node.kind === SyntaxKind.ImportType ? node : node.parent, type, symbol)) { + const props = type.getApparentProperties(); + for (const symbol of props) { + if (typeChecker.isValidPropertyAccessForCompletions(node.kind === SyntaxKind.ImportType ? node : node.parent, type, symbol, props.length > 20)) { addPropertySymbol(symbol); } }