@@ -5949,24 +5949,6 @@ namespace ts {
59495949 }
59505950 }
59515951
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- }
59705952
59715953 // Synthesize declarations for a symbol - might be an Interface, a Class, a Namespace, a Type, a Variable (const, let, or var), an Alias
59725954 // or a merge of some number of those.
@@ -6009,14 +5991,14 @@ namespace ts {
60095991 if (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property)
60105992 && symbol.escapedName !== InternalSymbolName.ExportEquals
60115993 && !(symbol.flags & SymbolFlags.Prototype)
6012- && !isEffectiveClassSymbol (symbol)
5994+ && !(symbol.flags & SymbolFlags.Class )
60135995 && !isConstMergedWithNSPrintableAsSignatureMerge) {
60145996 serializeVariableOrProperty(symbol, symbolName, isPrivate, needsPostExportDefault, propertyAsAlias, modifierFlags);
60155997 }
60165998 if (symbol.flags & SymbolFlags.Enum) {
60175999 serializeEnum(symbol, symbolName, modifierFlags);
60186000 }
6019- if (isEffectiveClassSymbol( symbol) ) {
6001+ if (symbol.flags & SymbolFlags.Class ) {
60206002 if (symbol.flags & SymbolFlags.Property && isBinaryExpression(symbol.valueDeclaration.parent) && isClassExpression(symbol.valueDeclaration.parent.right)) {
60216003 // Looks like a `module.exports.Sub = class {}` - if we serialize `symbol` as a class, the result will have no members,
60226004 // since the classiness is actually from the target of the effective alias the symbol is. yes. A BlockScopedVariable|Class|Property
@@ -6336,7 +6318,8 @@ namespace ts {
63366318 const baseTypes = getBaseTypes(classType);
63376319 const implementsTypes = getImplementsTypes(classType);
63386320 const staticType = getTypeOfSymbol(symbol);
6339- const staticBaseType = staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration)
6321+ const isClass = !!staticType.symbol?.valueDeclaration && isClassLike(staticType.symbol.valueDeclaration);
6322+ const staticBaseType = isClass
63406323 ? getBaseConstructorTypeOfClass(staticType as InterfaceType)
63416324 : anyType;
63426325 const heritageClauses = [
@@ -6374,7 +6357,17 @@ namespace ts {
63746357 const staticMembers = flatMap(
63756358 filter(getPropertiesOfType(staticType), p => !(p.flags & SymbolFlags.Prototype) && p.escapedName !== "prototype" && !isNamespaceMember(p)),
63766359 p => serializePropertySymbolForClass(p, /*isStatic*/ true, staticBaseType));
6377- const constructors = serializeSignatures(SignatureKind.Construct, staticType, baseTypes[0], SyntaxKind.Constructor) as ConstructorDeclaration[];
6360+ // When we encounter an `X.prototype.y` assignment in a JS file, we bind `X` as a class regardless as to whether
6361+ // the value is ever initialized with a class or function-like value. For cases where `X` could never be
6362+ // created via `new`, we will inject a `private constructor()` declaration to indicate it is not createable.
6363+ const isNonConstructableClassLikeInJsFile =
6364+ !isClass &&
6365+ !!symbol.valueDeclaration &&
6366+ isInJSFile(symbol.valueDeclaration) &&
6367+ !some(getSignaturesOfType(staticType, SignatureKind.Construct));
6368+ const constructors = isNonConstructableClassLikeInJsFile ?
6369+ [createConstructor(/*decorators*/ undefined, createModifiersFromModifierFlags(ModifierFlags.Private), [], undefined)] :
6370+ serializeSignatures(SignatureKind.Construct, staticType, baseTypes[0], SyntaxKind.Constructor) as ConstructorDeclaration[];
63786371 for (const c of constructors) {
63796372 // A constructor's return type and type parameters are supposed to be controlled by the enclosing class declaration
63806373 // `signatureToSignatureDeclarationHelper` appends them regardless, so for now we delete them here
0 commit comments