Skip to content

Commit 809df94

Browse files
committed
Avoid the double symbol for names that are explicitly exported
Fixes microsoft#33575.
1 parent bae111f commit 809df94

22 files changed

+421
-2
lines changed

src/compiler/binder.ts

+15-2
Original file line numberDiff line numberDiff line change
@@ -567,8 +567,10 @@ namespace ts {
567567
// and this case is specially handled. Module augmentations should only be merged with original module definition
568568
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
569569
if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
570-
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypeAlias(node)) {
571-
if (!container.locals || (hasSyntacticModifier(node, ModifierFlags.Default) && !getDeclarationName(node))) {
570+
const declarationName = getDeclarationName(node);
571+
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext))
572+
|| (isJSDocTypeAlias(node) && !nameIsExported(container, declarationName))) {
573+
if (!container.locals || (hasSyntacticModifier(node, ModifierFlags.Default) && !declarationName)) {
572574
return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
573575
}
574576
const exportKind = symbolFlags & SymbolFlags.Value ? SymbolFlags.ExportValue : 0;
@@ -583,6 +585,17 @@ namespace ts {
583585
}
584586
}
585587

588+
function nameIsExported(container: Node, name: __String | undefined): boolean {
589+
if (!name) return false;
590+
return arrayFrom(container.symbol.exports!.values()).some(sym =>
591+
sym.declarations.some(decl => {
592+
const expSym = isExportAssignment(decl) ? decl.expression
593+
: isExportSpecifier(decl) ? decl.propertyName
594+
: undefined;
595+
return expSym && isIdentifier(expSym) && expSym.escapedText === name;
596+
}));
597+
}
598+
586599
// All container nodes are kept on a linked list in declaration order. This list is used by
587600
// the getLocalNameOfContainer function in the type checker to validate that the local name
588601
// used for a container is unique.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
const X = { a: 1, m: 1 };
4+
>X : Symbol(X, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
5+
>a : Symbol(a, Decl(def.js, 1, 11))
6+
>m : Symbol(m, Decl(def.js, 1, 17))
7+
8+
export { X as default };
9+
>X : Symbol(X, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
10+
>default : Symbol(default, Decl(def.js, 2, 8))
11+
12+
=== tests/cases/conformance/jsdoc/use.js ===
13+
import X from "./def";
14+
>X : Symbol(X, Decl(use.js, 0, 6))
15+
16+
/** @type {X} */
17+
const n = 1;
18+
>n : Symbol(n, Decl(use.js, 3, 5))
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
const X = { a: 1, m: 1 };
4+
>X : { a: number; m: number; }
5+
>{ a: 1, m: 1 } : { a: number; m: number; }
6+
>a : number
7+
>1 : 1
8+
>m : number
9+
>1 : 1
10+
11+
export { X as default };
12+
>X : { a: number; m: number; }
13+
>default : { a: number; m: number; }
14+
15+
=== tests/cases/conformance/jsdoc/use.js ===
16+
import X from "./def";
17+
>X : { a: number; m: number; }
18+
19+
/** @type {X} */
20+
const n = 1;
21+
>n : number
22+
>1 : 1
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} Y */
3+
const Y = { a: 1, m: 1 };
4+
>Y : Symbol(Y, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
5+
>a : Symbol(a, Decl(def.js, 1, 11))
6+
>m : Symbol(m, Decl(def.js, 1, 17))
7+
8+
export { Y as X };
9+
>Y : Symbol(Y, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
10+
>X : Symbol(X, Decl(def.js, 2, 8))
11+
12+
=== tests/cases/conformance/jsdoc/use.js ===
13+
import { X } from "./def";
14+
>X : Symbol(X, Decl(use.js, 0, 8))
15+
16+
/** @type {X} */
17+
const n = 1;
18+
>n : Symbol(n, Decl(use.js, 3, 5))
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} Y */
3+
const Y = { a: 1, m: 1 };
4+
>Y : { a: number; m: number; }
5+
>{ a: 1, m: 1 } : { a: number; m: number; }
6+
>a : number
7+
>1 : 1
8+
>m : number
9+
>1 : 1
10+
11+
export { Y as X };
12+
>Y : { a: number; m: number; }
13+
>X : { a: number; m: number; }
14+
15+
=== tests/cases/conformance/jsdoc/use.js ===
16+
import { X } from "./def";
17+
>X : { a: number; m: number; }
18+
19+
/** @type {X} */
20+
const n = 1;
21+
>n : number
22+
>1 : 1
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @enum {number} */
3+
const MyEnum = {
4+
>MyEnum : Symbol(MyEnum, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
5+
6+
a: 1,
7+
>a : Symbol(a, Decl(def.js, 1, 16))
8+
9+
b: 2
10+
>b : Symbol(b, Decl(def.js, 2, 7))
11+
12+
};
13+
export default MyEnum;
14+
>MyEnum : Symbol(MyEnum, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
15+
16+
=== tests/cases/conformance/jsdoc/use.js ===
17+
import MyEnum from "./def";
18+
>MyEnum : Symbol(MyEnum, Decl(use.js, 0, 6))
19+
20+
/** @type {MyEnum} */
21+
const v = MyEnum.b;
22+
>v : Symbol(v, Decl(use.js, 3, 5))
23+
>MyEnum.b : Symbol(b, Decl(def.js, 2, 7))
24+
>MyEnum : Symbol(MyEnum, Decl(use.js, 0, 6))
25+
>b : Symbol(b, Decl(def.js, 2, 7))
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @enum {number} */
3+
const MyEnum = {
4+
>MyEnum : { a: number; b: number; }
5+
>{ a: 1, b: 2} : { a: number; b: number; }
6+
7+
a: 1,
8+
>a : number
9+
>1 : 1
10+
11+
b: 2
12+
>b : number
13+
>2 : 2
14+
15+
};
16+
export default MyEnum;
17+
>MyEnum : number
18+
19+
=== tests/cases/conformance/jsdoc/use.js ===
20+
import MyEnum from "./def";
21+
>MyEnum : { a: number; b: number; }
22+
23+
/** @type {MyEnum} */
24+
const v = MyEnum.b;
25+
>v : number
26+
>MyEnum.b : number
27+
>MyEnum : { a: number; b: number; }
28+
>b : number
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
const X = { a: 1, m: 1 };
4+
>X : Symbol(X, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
5+
>a : Symbol(a, Decl(def.js, 1, 11))
6+
>m : Symbol(m, Decl(def.js, 1, 17))
7+
8+
export default X;
9+
>X : Symbol(X, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
10+
11+
=== tests/cases/conformance/jsdoc/use.js ===
12+
import X from "./def";
13+
>X : Symbol(X, Decl(use.js, 0, 6))
14+
15+
/** @type {X} */
16+
const n = 1;
17+
>n : Symbol(n, Decl(use.js, 3, 5))
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
const X = { a: 1, m: 1 };
4+
>X : { a: number; m: number; }
5+
>{ a: 1, m: 1 } : { a: number; m: number; }
6+
>a : number
7+
>1 : 1
8+
>m : number
9+
>1 : 1
10+
11+
export default X;
12+
>X : number
13+
14+
=== tests/cases/conformance/jsdoc/use.js ===
15+
import X from "./def";
16+
>X : { a: number; m: number; }
17+
18+
/** @type {X} */
19+
const n = 1;
20+
>n : number
21+
>1 : 1
22+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
export const { X, Y } = { X: { a: 1, m: 1 }, Y: "why" };
4+
>X : Symbol(X, Decl(def.js, 1, 14), Decl(def.js, 0, 4))
5+
>Y : Symbol(Y, Decl(def.js, 1, 17))
6+
>X : Symbol(X, Decl(def.js, 1, 25))
7+
>a : Symbol(a, Decl(def.js, 1, 30))
8+
>m : Symbol(m, Decl(def.js, 1, 36))
9+
>Y : Symbol(Y, Decl(def.js, 1, 44))
10+
11+
=== tests/cases/conformance/jsdoc/use.js ===
12+
import { X } from "./def";
13+
>X : Symbol(X, Decl(use.js, 0, 8))
14+
15+
/** @type {X} */
16+
const n = 1;
17+
>n : Symbol(n, Decl(use.js, 3, 5))
18+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
export const { X, Y } = { X: { a: 1, m: 1 }, Y: "why" };
4+
>X : { a: number; m: number; }
5+
>Y : string
6+
>{ X: { a: 1, m: 1 }, Y: "why" } : { X: { a: number; m: number; }; Y: string; }
7+
>X : { a: number; m: number; }
8+
>{ a: 1, m: 1 } : { a: number; m: number; }
9+
>a : number
10+
>1 : 1
11+
>m : number
12+
>1 : 1
13+
>Y : string
14+
>"why" : "why"
15+
16+
=== tests/cases/conformance/jsdoc/use.js ===
17+
import { X } from "./def";
18+
>X : { a: number; m: number; }
19+
20+
/** @type {X} */
21+
const n = 1;
22+
>n : number
23+
>1 : 1
24+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
export let X = { a: 1, m: 1 };
4+
>X : Symbol(X, Decl(def.js, 1, 10), Decl(def.js, 0, 4))
5+
>a : Symbol(a, Decl(def.js, 1, 16))
6+
>m : Symbol(m, Decl(def.js, 1, 22))
7+
8+
=== tests/cases/conformance/jsdoc/use.js ===
9+
import { X } from "./def";
10+
>X : Symbol(X, Decl(use.js, 0, 8))
11+
12+
/** @type {X} */
13+
const n = 1;
14+
>n : Symbol(n, Decl(use.js, 3, 5))
15+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
=== tests/cases/conformance/jsdoc/def.js ===
2+
/** @typedef {number} X */
3+
export let X = { a: 1, m: 1 };
4+
>X : { a: number; m: number; }
5+
>{ a: 1, m: 1 } : { a: number; m: number; }
6+
>a : number
7+
>1 : 1
8+
>m : number
9+
>1 : 1
10+
11+
=== tests/cases/conformance/jsdoc/use.js ===
12+
import { X } from "./def";
13+
>X : { a: number; m: number; }
14+
15+
/** @type {X} */
16+
const n = 1;
17+
>n : number
18+
>1 : 1
19+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/conformance/jsdoc/use.js ===
2+
const X = require("./def");
3+
>X : Symbol(X, Decl(use.js, 0, 5))
4+
>require : Symbol(require)
5+
>"./def" : Symbol("tests/cases/conformance/jsdoc/def", Decl(def.js, 0, 0))
6+
7+
/** @type {X} */
8+
const n = 1;
9+
>n : Symbol(n, Decl(use.js, 3, 5))
10+
11+
=== tests/cases/conformance/jsdoc/def.js ===
12+
/** @typedef {number} X */
13+
const X = { a: 1, m: 1 };
14+
>X : Symbol(X, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
15+
>a : Symbol(a, Decl(def.js, 1, 11))
16+
>m : Symbol(m, Decl(def.js, 1, 17))
17+
18+
module.exports = X;
19+
>module.exports : Symbol("tests/cases/conformance/jsdoc/def", Decl(def.js, 0, 0))
20+
>module : Symbol(export=, Decl(def.js, 1, 25))
21+
>exports : Symbol(export=, Decl(def.js, 1, 25))
22+
>X : Symbol(X, Decl(def.js, 1, 5), Decl(def.js, 0, 4))
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
=== tests/cases/conformance/jsdoc/use.js ===
2+
const X = require("./def");
3+
>X : { a: number; m: number; }
4+
>require("./def") : { a: number; m: number; }
5+
>require : any
6+
>"./def" : "./def"
7+
8+
/** @type {X} */
9+
const n = 1;
10+
>n : error
11+
>1 : 1
12+
13+
=== tests/cases/conformance/jsdoc/def.js ===
14+
/** @typedef {number} X */
15+
const X = { a: 1, m: 1 };
16+
>X : { a: number; m: number; }
17+
>{ a: 1, m: 1 } : { a: number; m: number; }
18+
>a : number
19+
>1 : 1
20+
>m : number
21+
>1 : 1
22+
23+
module.exports = X;
24+
>module.exports = X : { a: number; m: number; }
25+
>module.exports : { a: number; m: number; }
26+
>module : { "\"tests/cases/conformance/jsdoc/def\"": { a: number; m: number; }; }
27+
>exports : { a: number; m: number; }
28+
>X : { a: number; m: number; }
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
5+
// @Filename: def.js
6+
/** @typedef {number} X */
7+
const X = { a: 1, m: 1 };
8+
export { X as default };
9+
10+
// @Filename: use.js
11+
import X from "./def";
12+
13+
/** @type {X} */
14+
const n = 1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
5+
// @Filename: def.js
6+
/** @typedef {number} Y */
7+
const Y = { a: 1, m: 1 };
8+
export { Y as X };
9+
10+
// @Filename: use.js
11+
import { X } from "./def";
12+
13+
/** @type {X} */
14+
const n = 1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @noEmit: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
5+
// @Filename: def.js
6+
/** @enum {number} */
7+
const MyEnum = {
8+
a: 1,
9+
b: 2
10+
};
11+
export default MyEnum;
12+
13+
// @Filename: use.js
14+
import MyEnum from "./def";
15+
16+
/** @type {MyEnum} */
17+
const v = MyEnum.b;

0 commit comments

Comments
 (0)