Skip to content

Commit 4283428

Browse files
authored
Fix export binding of namespaced typedefs (#40980)
The binder incorrectly rejected implicit namespace declarations in typedefs.
1 parent 4dc7e59 commit 4283428

8 files changed

+80
-17
lines changed

src/compiler/binder.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,9 @@ namespace ts {
586586
}
587587

588588
function jsdocTreatAsExported(node: Node) {
589+
if (node.parent && isModuleDeclaration(node)) {
590+
node = node.parent;
591+
}
589592
if (!isJSDocTypeAlias(node)) return false;
590593
// jsdoc typedef handling is a bit of a doozy, but to summarize, treat the typedef as exported if:
591594
// 1. It has an explicit name (since by default typedefs are always directly exported, either at the top level or in a container), or

tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,6 @@ export {testFn, testFnTypes};
5454

5555

5656
//// [file.d.ts]
57-
/**
58-
* @namespace myTypes
59-
* @global
60-
* @type {Object<string,*>}
61-
*/
62-
export const myTypes: {
63-
[x: string]: any;
64-
};
6557
export namespace myTypes {
6658
type typeA = string | RegExp | (string | RegExp)[];
6759
type typeB = {
@@ -76,7 +68,18 @@ export namespace myTypes {
7668
};
7769
type typeC = Function | typeB;
7870
}
71+
/**
72+
* @namespace myTypes
73+
* @global
74+
* @type {Object<string,*>}
75+
*/
76+
export const myTypes: {
77+
[x: string]: any;
78+
};
7979
//// [file2.d.ts]
80+
export namespace testFnTypes {
81+
type input = boolean | Function | myTypes.typeB;
82+
}
8083
/** @typedef {boolean|myTypes.typeC} testFnTypes.input */
8184
/**
8285
* @function testFn
@@ -85,6 +88,7 @@ export namespace myTypes {
8588
* @returns {number|null} Result.
8689
*/
8790
export function testFn(input: testFnTypes.input): number | null;
91+
import { myTypes } from "./file.js";
8892
/**
8993
* @namespace testFnTypes
9094
* @global
@@ -93,7 +97,3 @@ export function testFn(input: testFnTypes.input): number | null;
9397
export const testFnTypes: {
9498
[x: string]: any;
9599
};
96-
export namespace testFnTypes {
97-
type input = boolean | Function | myTypes.typeB;
98-
}
99-
import { myTypes } from "./file.js";

tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.symbols

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const myTypes = {
2121
/** @typedef {myTypes.typeB|Function} myTypes.typeC */
2222

2323
export {myTypes};
24-
>myTypes : Symbol(myTypes, Decl(file.js, 19, 8))
24+
>myTypes : Symbol(myTypes, Decl(file.js, 19, 8), Decl(file.js, 9, 50), Decl(file.js, 12, 12), Decl(file.js, 17, 38))
2525

2626
=== tests/cases/conformance/jsdoc/declarations/file2.js ===
2727
import {myTypes} from './file.js';
@@ -63,5 +63,5 @@ function testFn(input) {
6363

6464
export {testFn, testFnTypes};
6565
>testFn : Symbol(testFn, Decl(file2.js, 27, 8))
66-
>testFnTypes : Symbol(testFnTypes, Decl(file2.js, 27, 15))
66+
>testFnTypes : Symbol(testFnTypes, Decl(file2.js, 27, 15), Decl(file2.js, 11, 37))
6767

tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export {myTypes};
2626

2727
=== tests/cases/conformance/jsdoc/declarations/file2.js ===
2828
import {myTypes} from './file.js';
29-
>myTypes : { [x: string]: any; }
29+
>myTypes : any
3030

3131
/**
3232
* @namespace testFnTypes
@@ -50,12 +50,12 @@ const testFnTypes = {
5050
*/
5151
function testFn(input) {
5252
>testFn : (input: testFnTypes.input) => number | null
53-
>input : boolean | Function | myTypes.typeB
53+
>input : import("tests/cases/conformance/jsdoc/declarations/file2").testFnTypes.input
5454

5555
if (typeof input === 'number') {
5656
>typeof input === 'number' : boolean
5757
>typeof input : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function"
58-
>input : boolean | Function | myTypes.typeB
58+
>input : import("tests/cases/conformance/jsdoc/declarations/file2").testFnTypes.input
5959
>'number' : "number"
6060

6161
return 2 * input;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportNamespacedType.ts] ////
2+
3+
//// [file.js]
4+
import { dummy } from './mod1'
5+
/** @type {import('./mod1').Dotted.Name} - should work */
6+
var dot2
7+
8+
//// [mod1.js]
9+
/** @typedef {number} Dotted.Name */
10+
export var dummy = 1
11+
12+
13+
14+
15+
//// [mod1.d.ts]
16+
/** @typedef {number} Dotted.Name */
17+
export var dummy: number;
18+
export namespace Dotted {
19+
type Name = number;
20+
}
21+
//// [file.d.ts]
22+
export {};
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
2+
import { dummy } from './mod1'
3+
>dummy : Symbol(dummy, Decl(file.js, 0, 8))
4+
5+
/** @type {import('./mod1').Dotted.Name} - should work */
6+
var dot2
7+
>dot2 : Symbol(dot2, Decl(file.js, 2, 3))
8+
9+
=== tests/cases/conformance/jsdoc/declarations/mod1.js ===
10+
/** @typedef {number} Dotted.Name */
11+
export var dummy = 1
12+
>dummy : Symbol(dummy, Decl(mod1.js, 1, 10))
13+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=== tests/cases/conformance/jsdoc/declarations/file.js ===
2+
import { dummy } from './mod1'
3+
>dummy : number
4+
5+
/** @type {import('./mod1').Dotted.Name} - should work */
6+
var dot2
7+
>dot2 : number
8+
9+
=== tests/cases/conformance/jsdoc/declarations/mod1.js ===
10+
/** @typedef {number} Dotted.Name */
11+
export var dummy = 1
12+
>dummy : number
13+
>1 : 1
14+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// @declaration: true
2+
// @emitDeclarationOnly: true
3+
// @checkJs: true
4+
// @filename: file.js
5+
import { dummy } from './mod1'
6+
/** @type {import('./mod1').Dotted.Name} - should work */
7+
var dot2
8+
9+
// @filename: mod1.js
10+
/** @typedef {number} Dotted.Name */
11+
export var dummy = 1

0 commit comments

Comments
 (0)