@@ -5042,7 +5042,7 @@ namespace ts {
5042
5042
}
5043
5043
if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams &&
5044
5044
type.flags & TypeFlags.TypeParameter &&
5045
- !isTypeSymbolAccessible (type.symbol , context.enclosingDeclaration )) {
5045
+ typeParameterIsCachedOrNotAccessible (type, context)) {
5046
5046
const name = typeParameterToName(type, context);
5047
5047
context.approximateLength += idText(name).length;
5048
5048
return factory.createTypeReferenceNode(factory.createIdentifier(idText(name)), /*typeArguments*/ undefined);
@@ -5826,6 +5826,22 @@ namespace ts {
5826
5826
typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter, context));
5827
5827
}
5828
5828
5829
+ // For regular function/method declarations, the enclosing declaration will already be signature.declaration,
5830
+ // so this is a no-op, but for arrow functions and function expressions, the enclosing declaration will be
5831
+ // the declaration that the arrow function / function expression is assigned to, which is not the right scope.
5832
+ //
5833
+ // If the parameters or return type include "typeof globalThis.paramName", using the wrong scope will lead
5834
+ // us to believe that we can emit "typeof paramName" instead, even though that would refer to the parameter,
5835
+ // not the global. Make sure we are in the right scope by changing the enclosingDeclaration to the function.
5836
+ //
5837
+ // We check that this signature's declaration is within the existing enclosing declaration so we don't pull
5838
+ // in types from other files; if it is outside of the enclosing declaration, then we shouldn't be able to
5839
+ // access those parameter types via typeof anyway.
5840
+ const saveEnclosingDeclaration = context.enclosingDeclaration;
5841
+ if (signature.declaration && saveEnclosingDeclaration && findAncestor(signature.declaration, (n) => n === saveEnclosingDeclaration)) {
5842
+ context.enclosingDeclaration = signature.declaration;
5843
+ }
5844
+
5829
5845
const expandedParams = getExpandedParameters(signature, /*skipUnionExpanding*/ true)[0];
5830
5846
// If the expanded parameter list had a variadic in a non-trailing position, don't expand it
5831
5847
const parameters = (some(expandedParams, p => p !== expandedParams[expandedParams.length - 1] && !!(getCheckFlags(p) & CheckFlags.RestParameter)) ? signature.parameters : expandedParams).map(parameter => symbolToParameterDeclaration(parameter, context, kind === SyntaxKind.Constructor, options?.privateSymbolVisitor, options?.bundledImports));
@@ -5882,6 +5898,7 @@ namespace ts {
5882
5898
node.typeArguments = factory.createNodeArray(typeArguments);
5883
5899
}
5884
5900
5901
+ context.enclosingDeclaration = saveEnclosingDeclaration;
5885
5902
return node;
5886
5903
}
5887
5904
@@ -6366,13 +6383,28 @@ namespace ts {
6366
6383
return false;
6367
6384
}
6368
6385
6369
- function typeParameterToName(type: TypeParameter, context: NodeBuilderContext) {
6386
+ // Returns true if this type parameter should be converted to a name via typeParameterToName,
6387
+ // either because it is not accessible, or because it's a use of a type variable that has
6388
+ // already been rewritten by typeParameterToName and so needs that rewritten name.
6389
+ function typeParameterIsCachedOrNotAccessible(type: TypeParameter, context: NodeBuilderContext) {
6390
+ return !!getCachedTypeParameterName(type, context) || !isTypeSymbolAccessible(type.symbol, context.enclosingDeclaration);
6391
+ }
6392
+
6393
+ function getCachedTypeParameterName(type: TypeParameter, context: NodeBuilderContext) {
6370
6394
if (context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams && context.typeParameterNames) {
6371
6395
const cached = context.typeParameterNames.get(getTypeId(type));
6372
6396
if (cached) {
6373
6397
return cached;
6374
6398
}
6375
6399
}
6400
+ return undefined;
6401
+ }
6402
+
6403
+ function typeParameterToName(type: TypeParameter, context: NodeBuilderContext) {
6404
+ const cached = getCachedTypeParameterName(type, context);
6405
+ if (cached) {
6406
+ return cached;
6407
+ }
6376
6408
let result = symbolToName(type.symbol, context, SymbolFlags.Type, /*expectsIdentifier*/ true);
6377
6409
if (!(result.kind & SyntaxKind.Identifier)) {
6378
6410
return factory.createIdentifier("(Missing type parameter)");
@@ -6630,7 +6662,7 @@ namespace ts {
6630
6662
}
6631
6663
if (isIdentifier(node)) {
6632
6664
const type = getDeclaredTypeOfSymbol(sym);
6633
- const name = sym.flags & SymbolFlags.TypeParameter && !isTypeSymbolAccessible (type.symbol , context.enclosingDeclaration ) ? typeParameterToName(type, context) : factory.cloneNode(node);
6665
+ const name = sym.flags & SymbolFlags.TypeParameter && typeParameterIsCachedOrNotAccessible (type, context) ? typeParameterToName(type, context) : factory.cloneNode(node);
6634
6666
name.symbol = sym; // for quickinfo, which uses identifier symbol information
6635
6667
return { introducesError, node: setEmitFlags(setOriginalNode(name, node), EmitFlags.NoAsciiEscaping) };
6636
6668
}
0 commit comments