@@ -8533,11 +8533,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8533
8533
...oldcontext,
8534
8534
usedSymbolNames: new Set(oldcontext.usedSymbolNames),
8535
8535
remappedSymbolNames: new Map(),
8536
+ remappedSymbolReferences: new Map(oldcontext.remappedSymbolReferences?.entries()),
8536
8537
tracker: undefined!,
8537
8538
};
8538
8539
const tracker: SymbolTracker = {
8539
8540
...oldcontext.tracker.inner,
8540
8541
trackSymbol: (sym, decl, meaning) => {
8542
+ if (context.remappedSymbolNames?.has(getSymbolId(sym))) return false; // If the context has a remapped name for the symbol, it *should* mean it's been made visible
8541
8543
const accessibleResult = isSymbolAccessible(sym, decl, meaning, /*shouldComputeAliasesToMakeVisible*/ false);
8542
8544
if (accessibleResult.accessibility === SymbolAccessibility.Accessible) {
8543
8545
// Lookup the root symbol of the chain of refs we'll use to access it and serialize it
@@ -8790,9 +8792,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8790
8792
// If it's a property: emit `export default _default` with a `_default` prop
8791
8793
// If it's a class/interface/function: emit a class/interface/function with a `default` modifier
8792
8794
// These forms can merge, eg (`export default 12; export default interface A {}`)
8793
- function serializeSymbolWorker(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean): void {
8794
- const symbolName = unescapeLeadingUnderscores(symbol.escapedName );
8795
- const isDefault = symbol.escapedName === InternalSymbolName.Default;
8795
+ function serializeSymbolWorker(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean, escapedSymbolName = symbol.escapedName ): void {
8796
+ const symbolName = unescapeLeadingUnderscores(escapedSymbolName );
8797
+ const isDefault = escapedSymbolName === InternalSymbolName.Default;
8796
8798
if (isPrivate && !(context.flags & NodeBuilderFlags.AllowAnonymousIdentifier) && isStringANonContextualKeyword(symbolName) && !isDefault) {
8797
8799
// Oh no. We cannot use this symbol's name as it's name... It's likely some jsdoc had an invalid name like `export` or `default` :(
8798
8800
context.encounteredError = true;
@@ -8811,7 +8813,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8811
8813
const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0);
8812
8814
const isConstMergedWithNS = symbol.flags & SymbolFlags.Module &&
8813
8815
symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) &&
8814
- symbol.escapedName !== InternalSymbolName.ExportEquals;
8816
+ escapedSymbolName !== InternalSymbolName.ExportEquals;
8815
8817
const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol);
8816
8818
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) || isConstMergedWithNSPrintableAsSignatureMerge) {
8817
8819
serializeAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol, getInternalSymbolName(symbol, symbolName), modifierFlags);
@@ -8823,7 +8825,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8823
8825
// symbol of name `export=` which needs to be handled like an alias. It's not great, but it is what it is.
8824
8826
if (
8825
8827
symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property | SymbolFlags.Accessor)
8826
- && symbol.escapedName !== InternalSymbolName.ExportEquals
8828
+ && escapedSymbolName !== InternalSymbolName.ExportEquals
8827
8829
&& !(symbol.flags & SymbolFlags.Prototype)
8828
8830
&& !(symbol.flags & SymbolFlags.Class)
8829
8831
&& !(symbol.flags & SymbolFlags.Method)
@@ -8839,7 +8841,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
8839
8841
else {
8840
8842
const type = getTypeOfSymbol(symbol);
8841
8843
const localName = getInternalSymbolName(symbol, symbolName);
8842
- if (!(symbol.flags & SymbolFlags.Function) && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol)) {
8844
+ if (type.symbol && type.symbol !== symbol && type.symbol.flags & SymbolFlags.Function && some(type.symbol.declarations, isFunctionExpressionOrArrowFunction) && (type.symbol.members?.size || type.symbol.exports?.size)) {
8845
+ // assignment of a anonymous expando/class-like function, the func/ns/merge branch below won't trigger,
8846
+ // and the assignment form has to reference the unreachable anonymous type so will error.
8847
+ // Instead, serialize the type's symbol, but with the current symbol's name, rather than the anonymous one.
8848
+ if (!context.remappedSymbolReferences) {
8849
+ context.remappedSymbolReferences = new Map();
8850
+ }
8851
+ context.remappedSymbolReferences.set(getSymbolId(type.symbol), symbol); // save name remapping as local name for target symbol
8852
+ serializeSymbolWorker(type.symbol, isPrivate, propertyAsAlias, escapedSymbolName);
8853
+ context.remappedSymbolReferences.delete(getSymbolId(type.symbol));
8854
+ }
8855
+ else if (!(symbol.flags & SymbolFlags.Function) && isTypeRepresentableAsFunctionNamespaceMerge(type, symbol)) {
8843
8856
// If the type looks like a function declaration + ns could represent it, and it's type is sourced locally, rewrite it into a function declaration + ns
8844
8857
serializeAsFunctionNamespaceMerge(type, symbol, localName, modifierFlags);
8845
8858
}
@@ -10159,6 +10172,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
10159
10172
* It will also use a representation of a number as written instead of a decimal form, e.g. `0o11` instead of `9`.
10160
10173
*/
10161
10174
function getNameOfSymbolAsWritten(symbol: Symbol, context?: NodeBuilderContext): string {
10175
+ if (context?.remappedSymbolReferences?.has(getSymbolId(symbol))) {
10176
+ symbol = context.remappedSymbolReferences.get(getSymbolId(symbol))!;
10177
+ }
10162
10178
if (
10163
10179
context && symbol.escapedName === InternalSymbolName.Default && !(context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope) &&
10164
10180
// If it's not the first part of an entity name, it must print as `default`
@@ -49986,6 +50002,7 @@ interface NodeBuilderContext {
49986
50002
typeParameterNamesByTextNextNameCount?: Map<string, number>;
49987
50003
usedSymbolNames?: Set<string>;
49988
50004
remappedSymbolNames?: Map<SymbolId, string>;
50005
+ remappedSymbolReferences?: Map<SymbolId, Symbol>;
49989
50006
reverseMappedStack?: ReverseMappedSymbol[];
49990
50007
}
49991
50008
0 commit comments