Skip to content

Commit 154c614

Browse files
authored
Allow functions to be printed structurally in declaration emit even when they have symbols (#21203)
* Allow functions to be printed structurally in declaration emit even when they have symbols * Implement CR feedback and fix lint
1 parent 7c7651d commit 154c614

10 files changed

+85
-11
lines changed

src/compiler/checker.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2531,6 +2531,11 @@ namespace ts {
25312531
return access.accessibility === SymbolAccessibility.Accessible;
25322532
}
25332533

2534+
function isValueSymbolAccessible(typeSymbol: Symbol, enclosingDeclaration: Node): boolean {
2535+
const access = isSymbolAccessible(typeSymbol, enclosingDeclaration, SymbolFlags.Value, /*shouldComputeAliasesToMakeVisible*/ false);
2536+
return access.accessibility === SymbolAccessibility.Accessible;
2537+
}
2538+
25342539
/**
25352540
* Check if the given symbol in given enclosing declaration is accessible and mark all associated alias to be visible if requested
25362541
*
@@ -2993,7 +2998,8 @@ namespace ts {
29932998
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
29942999
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
29953000
// typeof is allowed only for static/non local functions
2996-
return !!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || contains(context.symbolStack, symbol); // it is type of the symbol uses itself recursively
3001+
return (!!(context.flags & NodeBuilderFlags.UseTypeOfFunction) || contains(context.symbolStack, symbol)) && // it is type of the symbol uses itself recursively
3002+
(!(context.flags & NodeBuilderFlags.UseStructuralFallback) || isValueSymbolAccessible(symbol, context.enclosingDeclaration)); // And the build is going to succeed without visibility error or there is no structural fallback allowed
29973003
}
29983004
}
29993005
}

src/compiler/declarationEmitter.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ namespace ts {
358358
}
359359
else {
360360
errorNameNode = declaration.name;
361-
const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteDefaultSymbolWithoutName |
361+
const format = TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteDefaultSymbolWithoutName |
362362
TypeFormatFlags.WriteClassExpressionAsTypeLiteral |
363363
(shouldUseResolverType ? TypeFormatFlags.AddUndefined : 0);
364364
resolver.writeTypeOfDeclaration(declaration, enclosingDeclaration, format, writer);
@@ -378,7 +378,7 @@ namespace ts {
378378
resolver.writeReturnTypeOfSignatureDeclaration(
379379
signature,
380380
enclosingDeclaration,
381-
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral | TypeFormatFlags.WriteDefaultSymbolWithoutName,
381+
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteClassExpressionAsTypeLiteral | TypeFormatFlags.WriteDefaultSymbolWithoutName,
382382
writer);
383383
errorNameNode = undefined;
384384
}
@@ -643,7 +643,7 @@ namespace ts {
643643
resolver.writeTypeOfExpression(
644644
expr,
645645
enclosingDeclaration,
646-
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.WriteClassExpressionAsTypeLiteral | TypeFormatFlags.WriteDefaultSymbolWithoutName,
646+
TypeFormatFlags.UseTypeOfFunction | TypeFormatFlags.UseStructuralFallback | TypeFormatFlags.WriteClassExpressionAsTypeLiteral | TypeFormatFlags.WriteDefaultSymbolWithoutName,
647647
writer);
648648
write(";");
649649
writeLine();

src/compiler/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2934,6 +2934,7 @@ namespace ts {
29342934
NoTruncation = 1 << 0, // Don't truncate result
29352935
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
29362936
WriteDefaultSymbolWithoutName = 1 << 2, // Write `default`-named symbols as `default` instead of how they were written
2937+
UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
29372938
// empty space
29382939
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
29392940
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
@@ -2968,6 +2969,7 @@ namespace ts {
29682969
NoTruncation = 1 << 0, // Don't truncate typeToString result
29692970
WriteArrayAsGenericType = 1 << 1, // Write Array<T> instead T[]
29702971
WriteDefaultSymbolWithoutName = 1 << 2, // Write all `defaut`-named symbols as `default` instead of their written name
2972+
UseStructuralFallback = 1 << 3, // When an alias cannot be named by its symbol, rather than report an error, fallback to a structural printout if possible
29712973
// hole because there's a hole in node builder flags
29722974
WriteTypeArgumentsOfSignature = 1 << 5, // Write the type arguments instead of type parameters of the signature
29732975
UseFullyQualifiedType = 1 << 6, // Write out the fully qualified type name (eg. Module.Type, instead of Type)
@@ -2997,7 +2999,7 @@ namespace ts {
29972999
/** @deprecated */ WriteOwnNameForAnyLike = 0, // Does nothing
29983000

29993001
NodeBuilderFlagsMask =
3000-
NoTruncation | WriteArrayAsGenericType | WriteDefaultSymbolWithoutName | WriteTypeArgumentsOfSignature |
3002+
NoTruncation | WriteArrayAsGenericType | WriteDefaultSymbolWithoutName | UseStructuralFallback | WriteTypeArgumentsOfSignature |
30013003
UseFullyQualifiedType | SuppressAnyReturnType | MultilineObjectLiterals | WriteClassExpressionAsTypeLiteral |
30023004
UseTypeOfFunction | OmitParameterModifiers | UseAliasDefinedOutsideCurrentScope | AllowUniqueESSymbolType | InTypeAlias,
30033005
}

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,7 @@ declare namespace ts {
18001800
NoTruncation = 1,
18011801
WriteArrayAsGenericType = 2,
18021802
WriteDefaultSymbolWithoutName = 4,
1803+
UseStructuralFallback = 8,
18031804
WriteTypeArgumentsOfSignature = 32,
18041805
UseFullyQualifiedType = 64,
18051806
UseOnlyExternalAliasing = 128,
@@ -1826,6 +1827,7 @@ declare namespace ts {
18261827
NoTruncation = 1,
18271828
WriteArrayAsGenericType = 2,
18281829
WriteDefaultSymbolWithoutName = 4,
1830+
UseStructuralFallback = 8,
18291831
WriteTypeArgumentsOfSignature = 32,
18301832
UseFullyQualifiedType = 64,
18311833
SuppressAnyReturnType = 256,
@@ -1842,7 +1844,7 @@ declare namespace ts {
18421844
InFirstTypeArgument = 4194304,
18431845
InTypeAlias = 8388608,
18441846
/** @deprecated */ WriteOwnNameForAnyLike = 0,
1845-
NodeBuilderFlagsMask = 9469287,
1847+
NodeBuilderFlagsMask = 9469295,
18461848
}
18471849
enum SymbolFormatFlags {
18481850
None = 0,

tests/baselines/reference/api/typescript.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1800,6 +1800,7 @@ declare namespace ts {
18001800
NoTruncation = 1,
18011801
WriteArrayAsGenericType = 2,
18021802
WriteDefaultSymbolWithoutName = 4,
1803+
UseStructuralFallback = 8,
18031804
WriteTypeArgumentsOfSignature = 32,
18041805
UseFullyQualifiedType = 64,
18051806
UseOnlyExternalAliasing = 128,
@@ -1826,6 +1827,7 @@ declare namespace ts {
18261827
NoTruncation = 1,
18271828
WriteArrayAsGenericType = 2,
18281829
WriteDefaultSymbolWithoutName = 4,
1830+
UseStructuralFallback = 8,
18291831
WriteTypeArgumentsOfSignature = 32,
18301832
UseFullyQualifiedType = 64,
18311833
SuppressAnyReturnType = 256,
@@ -1842,7 +1844,7 @@ declare namespace ts {
18421844
InFirstTypeArgument = 4194304,
18431845
InTypeAlias = 8388608,
18441846
/** @deprecated */ WriteOwnNameForAnyLike = 0,
1845-
NodeBuilderFlagsMask = 9469287,
1847+
NodeBuilderFlagsMask = 9469295,
18461848
}
18471849
enum SymbolFormatFlags {
18481850
None = 0,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//// [declarationFunctionTypeNonlocalShouldNotBeAnError.ts]
2+
namespace foo {
3+
function bar(): void {}
4+
5+
export const obj = {
6+
bar
7+
}
8+
}
9+
10+
11+
//// [declarationFunctionTypeNonlocalShouldNotBeAnError.js]
12+
var foo;
13+
(function (foo) {
14+
function bar() { }
15+
foo.obj = {
16+
bar: bar
17+
};
18+
})(foo || (foo = {}));
19+
20+
21+
//// [declarationFunctionTypeNonlocalShouldNotBeAnError.d.ts]
22+
declare namespace foo {
23+
const obj: {
24+
bar: () => void;
25+
};
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/compiler/declarationFunctionTypeNonlocalShouldNotBeAnError.ts ===
2+
namespace foo {
3+
>foo : Symbol(foo, Decl(declarationFunctionTypeNonlocalShouldNotBeAnError.ts, 0, 0))
4+
5+
function bar(): void {}
6+
>bar : Symbol(bar, Decl(declarationFunctionTypeNonlocalShouldNotBeAnError.ts, 0, 15))
7+
8+
export const obj = {
9+
>obj : Symbol(obj, Decl(declarationFunctionTypeNonlocalShouldNotBeAnError.ts, 3, 16))
10+
11+
bar
12+
>bar : Symbol(bar, Decl(declarationFunctionTypeNonlocalShouldNotBeAnError.ts, 3, 24))
13+
}
14+
}
15+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
=== tests/cases/compiler/declarationFunctionTypeNonlocalShouldNotBeAnError.ts ===
2+
namespace foo {
3+
>foo : typeof foo
4+
5+
function bar(): void {}
6+
>bar : () => void
7+
8+
export const obj = {
9+
>obj : { bar: () => void; }
10+
>{ bar } : { bar: () => void; }
11+
12+
bar
13+
>bar : () => void
14+
}
15+
}
16+
Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
tests/cases/compiler/privacyCheckTypeOfFunction.ts(3,22): error TS4025: Exported variable 'x' has or is using private name 'foo'.
2-
tests/cases/compiler/privacyCheckTypeOfFunction.ts(4,12): error TS4025: Exported variable 'b' has or is using private name 'foo'.
32

43

5-
==== tests/cases/compiler/privacyCheckTypeOfFunction.ts (2 errors) ====
4+
==== tests/cases/compiler/privacyCheckTypeOfFunction.ts (1 errors) ====
65
function foo() {
76
}
87
export var x: typeof foo;
98
~~~
109
!!! error TS4025: Exported variable 'x' has or is using private name 'foo'.
1110
export var b = foo;
12-
~
13-
!!! error TS4025: Exported variable 'b' has or is using private name 'foo'.
1411

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// @declaration: true
2+
namespace foo {
3+
function bar(): void {}
4+
5+
export const obj = {
6+
bar
7+
}
8+
}

0 commit comments

Comments
 (0)