Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion tsc/internal/checker/nodebuilderimpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -2680,7 +2680,7 @@ func (b *NodeBuilderImpl) createTypeNodesFromResolvedType(resolvedType *Structur
continue
}
if getDeclarationModifierFlagsFromSymbol(propertySymbol)&(ast.ModifierFlagsPrivate|ast.ModifierFlagsProtected) != 0 {
b.ctx.tracker.ReportPrivateInBaseOfClassExpression(propertySymbol.Name)
b.ctx.tracker.ReportPrivateInBaseOfClassExpression(escapeInternalNameForTS4094(propertySymbol.Name))
}
if IsPrivateIdentifierSymbol(propertySymbol) {
b.ctx.tracker.ReportPrivateInBaseOfClassExpression(ast.SymbolName(propertySymbol))
Expand Down Expand Up @@ -3635,3 +3635,19 @@ func (b *NodeBuilderImpl) lookupExpressionChainTypeArgumentNodes(chain []*ast.Sy
func (b *NodeBuilderImpl) shouldWriteTypeParametersInQualifiedName(chain []*ast.Symbol, index int) bool {
return b.ctx.flags&nodebuilder.FlagsWriteTypeParametersInQualifiedName != 0 && index < len(chain)-1
}

// escapeInternalNameForTS4094 prints unique-symbol names as "__@brand", not the "\xFE" sentinel
// and not the process-global "@<symbolId>" suffix (ast.nextSymbolId), which would flake baselines.
func escapeInternalNameForTS4094(name string) string {
escaped := ast.EscapeInternalSymbolName(name)
at := strings.LastIndexByte(escaped, '@')
if at <= 0 || at+1 >= len(escaped) {
return escaped
}
for i := at + 1; i < len(escaped); i++ {
if escaped[i] < '0' || escaped[i] > '9' {
return escaped
}
}
return escaped[:at]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
index.ts(3,14): error TS4023: Exported variable 'f' has or is using name 'brand' from external module "helper" but cannot be named.
index.ts(3,14): error TS4094: Property '__@brand' of exported anonymous class type may not be private or protected.


==== helper.ts (0 errors) ====
declare const brand: unique symbol;

class Foo {
private [brand]: number = 1;
}

export function makeFoo() {
return new Foo();
}

==== index.ts (2 errors) ====
import { makeFoo } from "./helper";

export const f = () => makeFoo();
~
!!! error TS4023: Exported variable 'f' has or is using name 'brand' from external module "helper" but cannot be named.
~
!!! error TS4094: Property '__@brand' of exported anonymous class type may not be private or protected.
!!! related TS9027 index.ts:3:14: Add a type annotation to the variable f.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//// [tests/cases/compiler/declarationEmitAnonymousClassUniqueSymbolPrivate.ts] ////

//// [helper.ts]
declare const brand: unique symbol;

class Foo {
private [brand]: number = 1;
}

export function makeFoo() {
return new Foo();
}

//// [index.ts]
import { makeFoo } from "./helper";

export const f = () => makeFoo();


//// [helper.js]
class Foo {
[brand] = 1;
}
export function makeFoo() {
return new Foo();
}
//// [index.js]
import { makeFoo } from "./helper";
export const f = () => makeFoo();


//// [helper.d.ts]
declare const brand: unique symbol;
declare class Foo {
private [brand];
}
export declare function makeFoo(): Foo;
export {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//// [tests/cases/compiler/declarationEmitAnonymousClassUniqueSymbolPrivate.ts] ////

=== helper.ts ===
declare const brand: unique symbol;
>brand : Symbol(brand, Decl(helper.ts, 0, 13))

class Foo {
>Foo : Symbol(Foo, Decl(helper.ts, 0, 35))

private [brand]: number = 1;
>[brand] : Symbol(Foo[brand], Decl(helper.ts, 2, 11))
>brand : Symbol(brand, Decl(helper.ts, 0, 13))
}

export function makeFoo() {
>makeFoo : Symbol(makeFoo, Decl(helper.ts, 4, 1))

return new Foo();
>Foo : Symbol(Foo, Decl(helper.ts, 0, 35))
}

=== index.ts ===
import { makeFoo } from "./helper";
>makeFoo : Symbol(makeFoo, Decl(index.ts, 0, 8))

export const f = () => makeFoo();
>f : Symbol(f, Decl(index.ts, 2, 12))
>makeFoo : Symbol(makeFoo, Decl(index.ts, 0, 8))

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//// [tests/cases/compiler/declarationEmitAnonymousClassUniqueSymbolPrivate.ts] ////

=== helper.ts ===
declare const brand: unique symbol;
>brand : unique symbol

class Foo {
>Foo : Foo

private [brand]: number = 1;
>[brand] : number
>brand : unique symbol
>1 : 1
}

export function makeFoo() {
>makeFoo : () => Foo

return new Foo();
>new Foo() : Foo
>Foo : typeof Foo
}

=== index.ts ===
import { makeFoo } from "./helper";
>makeFoo : () => Foo

export const f = () => makeFoo();
>f : () => Foo
>() => makeFoo() : () => Foo
>makeFoo() : Foo
>makeFoo : () => Foo

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// @declaration: true
// @filename: helper.ts
declare const brand: unique symbol;

class Foo {
private [brand]: number = 1;
}

export function makeFoo() {
return new Foo();
}

// @filename: index.ts
import { makeFoo } from "./helper";

export const f = () => makeFoo();