@@ -5949,6 +5949,25 @@ namespace ts {
5949
5949
}
5950
5950
}
5951
5951
5952
+ function isEffectiveClassSymbol(symbol: Symbol) {
5953
+ if (!(symbol.flags & SymbolFlags.Class)) {
5954
+ return false;
5955
+ }
5956
+ if (isInJSFile(symbol.valueDeclaration) && !isClassLike(symbol.valueDeclaration)) {
5957
+ // For a symbol that isn't syntactically a `class` in a JS file we have heuristics
5958
+ // that detect prototype assignments that indicate the symbol is *probably* a class.
5959
+ // Filter out any prototype assignments for non-class symbols, i.e.
5960
+ //
5961
+ // let A;
5962
+ // A = {};
5963
+ // A.prototype.b = {};
5964
+ const type = getTypeOfSymbol(symbol);
5965
+ return some(getSignaturesOfType(type, SignatureKind.Construct))
5966
+ || some(getSignaturesOfType(type, SignatureKind.Call));
5967
+ }
5968
+ return true;
5969
+ }
5970
+
5952
5971
// Synthesize declarations for a symbol - might be an Interface, a Class, a Namespace, a Type, a Variable (const, let, or var), an Alias
5953
5972
// or a merge of some number of those.
5954
5973
// An interesting challenge is ensuring that when classes merge with namespaces and interfaces, is keeping
@@ -5990,14 +6009,14 @@ namespace ts {
5990
6009
if (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property)
5991
6010
&& symbol.escapedName !== InternalSymbolName.ExportEquals
5992
6011
&& !(symbol.flags & SymbolFlags.Prototype)
5993
- && !(symbol.flags & SymbolFlags.Class )
6012
+ && !isEffectiveClassSymbol (symbol)
5994
6013
&& !isConstMergedWithNSPrintableAsSignatureMerge) {
5995
6014
serializeVariableOrProperty(symbol, symbolName, isPrivate, needsPostExportDefault, propertyAsAlias, modifierFlags);
5996
6015
}
5997
6016
if (symbol.flags & SymbolFlags.Enum) {
5998
6017
serializeEnum(symbol, symbolName, modifierFlags);
5999
6018
}
6000
- if (symbol.flags & SymbolFlags.Class ) {
6019
+ if (isEffectiveClassSymbol( symbol) ) {
6001
6020
if (symbol.flags & SymbolFlags.Property && isBinaryExpression(symbol.valueDeclaration.parent) && isClassExpression(symbol.valueDeclaration.parent.right)) {
6002
6021
// Looks like a `module.exports.Sub = class {}` - if we serialize `symbol` as a class, the result will have no members,
6003
6022
// since the classiness is actually from the target of the effective alias the symbol is. yes. A BlockScopedVariable|Class|Property
@@ -6317,7 +6336,9 @@ namespace ts {
6317
6336
const baseTypes = getBaseTypes(classType);
6318
6337
const implementsTypes = getImplementsTypes(classType);
6319
6338
const staticType = getTypeOfSymbol(symbol);
6320
- const staticBaseType = getBaseConstructorTypeOfClass(staticType as InterfaceType);
6339
+ const staticBaseType = staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration)
6340
+ ? getBaseConstructorTypeOfClass(staticType as InterfaceType)
6341
+ : anyType;
6321
6342
const heritageClauses = [
6322
6343
...!length(baseTypes) ? [] : [createHeritageClause(SyntaxKind.ExtendsKeyword, map(baseTypes, b => serializeBaseType(b, staticBaseType, localName)))],
6323
6344
...!length(implementsTypes) ? [] : [createHeritageClause(SyntaxKind.ImplementsKeyword, map(implementsTypes, b => serializeBaseType(b, staticBaseType, localName)))]
0 commit comments