From 6ee6e0269377764ed42ae45de041bac29d77cab1 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jul 2020 13:37:43 -0700 Subject: [PATCH 1/2] In JS declaration emit, move imports painted in nested contexts to the root private context --- src/compiler/checker.ts | 23 +++-- ...ationsImportAliasExposedWithinNamespace.js | 99 +++++++++++++++++++ ...sImportAliasExposedWithinNamespace.symbols | 67 +++++++++++++ ...onsImportAliasExposedWithinNamespace.types | 75 ++++++++++++++ ...ationsImportAliasExposedWithinNamespace.ts | 56 +++++++++++ 5 files changed, 313 insertions(+), 7 deletions(-) create mode 100644 tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js create mode 100644 tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.symbols create mode 100644 tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.types create mode 100644 tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespace.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5c31002cf2773..8f3009dc39ce9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5889,7 +5889,7 @@ namespace ts { const enclosingDeclaration = context.enclosingDeclaration!; let results: Statement[] = []; const visitedSymbols = new Set(); - let deferredPrivates: ESMap | undefined; + const deferredPrivatesStack: ESMap[] = []; const oldcontext = context; context = { ...oldcontext, @@ -6100,9 +6100,8 @@ namespace ts { } function visitSymbolTable(symbolTable: SymbolTable, suppressNewPrivateContext?: boolean, propertyAsAlias?: boolean) { - const oldDeferredPrivates = deferredPrivates; if (!suppressNewPrivateContext) { - deferredPrivates = new Map(); + deferredPrivatesStack.push(new Map()); } symbolTable.forEach((symbol: Symbol) => { serializeSymbol(symbol, /*isPrivate*/ false, !!propertyAsAlias); @@ -6111,11 +6110,11 @@ namespace ts { // deferredPrivates will be filled up by visiting the symbol table // And will continue to iterate as elements are added while visited `deferredPrivates` // (As that's how a map iterator is defined to work) - deferredPrivates!.forEach((symbol: Symbol) => { + deferredPrivatesStack[deferredPrivatesStack.length - 1].forEach((symbol: Symbol) => { serializeSymbol(symbol, /*isPrivate*/ true, !!propertyAsAlias); }); + deferredPrivatesStack.pop(); } - deferredPrivates = oldDeferredPrivates; } function serializeSymbol(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean) { @@ -6299,9 +6298,19 @@ namespace ts { function includePrivateSymbol(symbol: Symbol) { if (some(symbol.declarations, isParameterDeclaration)) return; - Debug.assertIsDefined(deferredPrivates); + Debug.assertIsDefined(deferredPrivatesStack[deferredPrivatesStack.length - 1]); getUnusedName(unescapeLeadingUnderscores(symbol.escapedName), symbol); // Call to cache unique name for symbol - deferredPrivates.set(getSymbolId(symbol), symbol); + // Blanket moving (import) aliases into the root private context should work, since imports are not valid within namespaces + // (so they must have been in the root to begin with if they were real imports) cjs `require` aliases (an upcoming feature) + // will throw a wrench in this, since those may have been nested, but we'll need to synthesize them in the outer scope + // anyway, as that's the only place the import they translate to is valid. In such a case, we might need to use a unique name + // for the moved import; which hopefully the above `getUnusedName` call should produce. + const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) && !some(symbol.declarations, d => + !!findAncestor(d, isExportDeclaration) || + isNamespaceExport(d) || + (isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference)) + ); + deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set(getSymbolId(symbol), symbol); } function isExportingScope(enclosingDeclaration: Node) { diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js new file mode 100644 index 0000000000000..2a80e817c499f --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.js @@ -0,0 +1,99 @@ +//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespace.ts] //// + +//// [file.js] +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +export {myTypes}; +//// [file2.js] +import {myTypes} from './file.js'; + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { + if (typeof input === 'number') { + return 2 * input; + } else { + return null; + } +} + +export {testFn, testFnTypes}; + + + +//// [file.d.ts] +/** + * @namespace myTypes + * @global + * @type {Object} + */ +export const myTypes: { + [x: string]: any; +}; +export namespace myTypes { + type typeA = string | RegExp | (string | RegExp)[]; + type typeB = { + /** + * - Prop 1. + */ + prop1: string | RegExp | (string | RegExp)[]; + /** + * - Prop 2. + */ + prop2: string; + }; + type typeC = Function | typeB; +} +//// [file2.d.ts] +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +export function testFn(input: boolean | Function | myTypes.typeB): number | null; +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +export const testFnTypes: { + [x: string]: any; +}; +export namespace testFnTypes { + type input = boolean | Function | myTypes.typeB; +} +import { myTypes } from "./file.js"; diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.symbols b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.symbols new file mode 100644 index 0000000000000..c12e398c008cf --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.symbols @@ -0,0 +1,67 @@ +=== tests/cases/conformance/jsdoc/declarations/file.js === +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { +>myTypes : Symbol(myTypes, Decl(file.js, 5, 5), Decl(file.js, 9, 50), Decl(file.js, 12, 12), Decl(file.js, 17, 38)) + + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +export {myTypes}; +>myTypes : Symbol(myTypes, Decl(file.js, 19, 8)) + +=== tests/cases/conformance/jsdoc/declarations/file2.js === +import {myTypes} from './file.js'; +>myTypes : Symbol(myTypes, Decl(file2.js, 0, 8)) + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { +>testFnTypes : Symbol(testFnTypes, Decl(file2.js, 7, 5), Decl(file2.js, 11, 37)) + + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { +>testFn : Symbol(testFn, Decl(file2.js, 9, 2)) +>input : Symbol(input, Decl(file2.js, 19, 16)) + + if (typeof input === 'number') { +>input : Symbol(input, Decl(file2.js, 19, 16)) + + return 2 * input; +>input : Symbol(input, Decl(file2.js, 19, 16)) + + } else { + return null; + } +} + +export {testFn, testFnTypes}; +>testFn : Symbol(testFn, Decl(file2.js, 27, 8)) +>testFnTypes : Symbol(testFnTypes, Decl(file2.js, 27, 15)) + diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.types b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.types new file mode 100644 index 0000000000000..6ae80a17fefb0 --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespace.types @@ -0,0 +1,75 @@ +=== tests/cases/conformance/jsdoc/declarations/file.js === +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { +>myTypes : { [x: string]: any; } +>{ // SOME PROPS HERE} : {} + + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +export {myTypes}; +>myTypes : { [x: string]: any; } + +=== tests/cases/conformance/jsdoc/declarations/file2.js === +import {myTypes} from './file.js'; +>myTypes : { [x: string]: any; } + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { +>testFnTypes : { [x: string]: any; } +>{ // SOME PROPS HERE} : {} + + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { +>testFn : (input: testFnTypes.input) => number | null +>input : boolean | Function | myTypes.typeB + + if (typeof input === 'number') { +>typeof input === 'number' : boolean +>typeof input : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>input : boolean | Function | myTypes.typeB +>'number' : "number" + + return 2 * input; +>2 * input : number +>2 : 2 +>input : never + + } else { + return null; +>null : null + } +} + +export {testFn, testFnTypes}; +>testFn : (input: boolean | Function | myTypes.typeB) => number +>testFnTypes : { [x: string]: any; } + diff --git a/tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespace.ts b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespace.ts new file mode 100644 index 0000000000000..3256f3970ba59 --- /dev/null +++ b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespace.ts @@ -0,0 +1,56 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @allowJs: true +// @checkJs: true +// @module: commonjs +// @target: es6 +// @filename: file.js +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +export {myTypes}; +// @filename: file2.js +import {myTypes} from './file.js'; + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { + if (typeof input === 'number') { + return 2 * input; + } else { + return null; + } +} + +export {testFn, testFnTypes}; \ No newline at end of file From 83fc2ebad5b386425e87e7adae20e1452a5e78e7 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 31 Jul 2020 11:30:05 -0700 Subject: [PATCH 2/2] Add test for nathan --- ...tAliasExposedWithinNamespaceCjs.errors.txt | 55 ++++++++++++ ...onsImportAliasExposedWithinNamespaceCjs.js | 79 +++++++++++++++++ ...portAliasExposedWithinNamespaceCjs.symbols | 75 ++++++++++++++++ ...ImportAliasExposedWithinNamespaceCjs.types | 87 +++++++++++++++++++ ...onsImportAliasExposedWithinNamespaceCjs.ts | 56 ++++++++++++ 5 files changed, 352 insertions(+) create mode 100644 tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.errors.txt create mode 100644 tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js create mode 100644 tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.symbols create mode 100644 tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.types create mode 100644 tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespaceCjs.ts diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.errors.txt b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.errors.txt new file mode 100644 index 0000000000000..af5809b27023f --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.errors.txt @@ -0,0 +1,55 @@ +tests/cases/conformance/jsdoc/declarations/file2.js(12,31): error TS2694: Namespace 'myTypes' has no exported member 'typeC'. + + +==== tests/cases/conformance/jsdoc/declarations/file2.js (1 errors) ==== + const {myTypes} = require('./file.js'); + + /** + * @namespace testFnTypes + * @global + * @type {Object} + */ + const testFnTypes = { + // SOME PROPS HERE + }; + + /** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + ~~~~~ +!!! error TS2694: Namespace 'myTypes' has no exported member 'typeC'. + + /** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ + function testFn(input) { + if (typeof input === 'number') { + return 2 * input; + } else { + return null; + } + } + + module.exports = {testFn, testFnTypes}; +==== tests/cases/conformance/jsdoc/declarations/file.js (0 errors) ==== + /** + * @namespace myTypes + * @global + * @type {Object} + */ + const myTypes = { + // SOME PROPS HERE + }; + + /** @typedef {string|RegExp|Array} myTypes.typeA */ + + /** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + + /** @typedef {myTypes.typeB|Function} myTypes.typeC */ + + exports.myTypes = myTypes; \ No newline at end of file diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js new file mode 100644 index 0000000000000..0c0e0ba34cc52 --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.js @@ -0,0 +1,79 @@ +//// [tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespaceCjs.ts] //// + +//// [file.js] +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +exports.myTypes = myTypes; +//// [file2.js] +const {myTypes} = require('./file.js'); + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { + if (typeof input === 'number') { + return 2 * input; + } else { + return null; + } +} + +module.exports = {testFn, testFnTypes}; + + + +//// [file.d.ts] +export var myTypes: { + [x: string]: any; +}; +//// [file2.d.ts] +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +export function testFn(input: any): number | null; +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +export const testFnTypes: { + [x: string]: any; +}; +export namespace testFnTypes { + type input = any; +} diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.symbols b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.symbols new file mode 100644 index 0000000000000..edaf1091131ba --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.symbols @@ -0,0 +1,75 @@ +=== tests/cases/conformance/jsdoc/declarations/file2.js === +const {myTypes} = require('./file.js'); +>myTypes : Symbol(myTypes, Decl(file2.js, 0, 7)) +>require : Symbol(require) +>'./file.js' : Symbol("tests/cases/conformance/jsdoc/declarations/file", Decl(file.js, 0, 0)) + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { +>testFnTypes : Symbol(testFnTypes, Decl(file2.js, 7, 5), Decl(file2.js, 11, 37)) + + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { +>testFn : Symbol(testFn, Decl(file2.js, 9, 2)) +>input : Symbol(input, Decl(file2.js, 19, 16)) + + if (typeof input === 'number') { +>input : Symbol(input, Decl(file2.js, 19, 16)) + + return 2 * input; +>input : Symbol(input, Decl(file2.js, 19, 16)) + + } else { + return null; + } +} + +module.exports = {testFn, testFnTypes}; +>module.exports : Symbol("tests/cases/conformance/jsdoc/declarations/file2", Decl(file2.js, 0, 0)) +>module : Symbol(export=, Decl(file2.js, 25, 1)) +>exports : Symbol(export=, Decl(file2.js, 25, 1)) +>testFn : Symbol(testFn, Decl(file2.js, 27, 18)) +>testFnTypes : Symbol(testFnTypes, Decl(file2.js, 27, 25)) + +=== tests/cases/conformance/jsdoc/declarations/file.js === +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { +>myTypes : Symbol(myTypes, Decl(file.js, 5, 5), Decl(file.js, 9, 50), Decl(file.js, 12, 12), Decl(file.js, 17, 38)) + + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +exports.myTypes = myTypes; +>exports.myTypes : Symbol(myTypes, Decl(file.js, 7, 2)) +>exports : Symbol(myTypes, Decl(file.js, 7, 2)) +>myTypes : Symbol(myTypes, Decl(file.js, 7, 2)) +>myTypes : Symbol(myTypes, Decl(file.js, 5, 5), Decl(file.js, 9, 50), Decl(file.js, 12, 12), Decl(file.js, 17, 38)) + diff --git a/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.types b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.types new file mode 100644 index 0000000000000..fd1aae4d8ca5e --- /dev/null +++ b/tests/baselines/reference/jsDeclarationsImportAliasExposedWithinNamespaceCjs.types @@ -0,0 +1,87 @@ +=== tests/cases/conformance/jsdoc/declarations/file2.js === +const {myTypes} = require('./file.js'); +>myTypes : { [x: string]: any; } +>require('./file.js') : typeof import("tests/cases/conformance/jsdoc/declarations/file") +>require : any +>'./file.js' : "./file.js" + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { +>testFnTypes : { [x: string]: any; } +>{ // SOME PROPS HERE} : {} + + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { +>testFn : (input: testFnTypes.input) => number | null +>input : any + + if (typeof input === 'number') { +>typeof input === 'number' : boolean +>typeof input : "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function" +>input : any +>'number' : "number" + + return 2 * input; +>2 * input : number +>2 : 2 +>input : number + + } else { + return null; +>null : null + } +} + +module.exports = {testFn, testFnTypes}; +>module.exports = {testFn, testFnTypes} : { testFn: (input: any) => number; testFnTypes: { [x: string]: any; }; } +>module.exports : { testFn: (input: any) => number; testFnTypes: { [x: string]: any; }; } +>module : { "\"tests/cases/conformance/jsdoc/declarations/file2\"": { testFn: (input: any) => number; testFnTypes: { [x: string]: any; }; }; } +>exports : { testFn: (input: any) => number; testFnTypes: { [x: string]: any; }; } +>{testFn, testFnTypes} : { testFn: (input: any) => number; testFnTypes: { [x: string]: any; }; } +>testFn : (input: any) => number +>testFnTypes : { [x: string]: any; } + +=== tests/cases/conformance/jsdoc/declarations/file.js === +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { +>myTypes : { [x: string]: any; } +>{ // SOME PROPS HERE} : {} + + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +exports.myTypes = myTypes; +>exports.myTypes = myTypes : { [x: string]: any; } +>exports.myTypes : { [x: string]: any; } +>exports : typeof import("tests/cases/conformance/jsdoc/declarations/file") +>myTypes : { [x: string]: any; } +>myTypes : { [x: string]: any; } + diff --git a/tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespaceCjs.ts b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespaceCjs.ts new file mode 100644 index 0000000000000..cd2a8d74731c0 --- /dev/null +++ b/tests/cases/conformance/jsdoc/declarations/jsDeclarationsImportAliasExposedWithinNamespaceCjs.ts @@ -0,0 +1,56 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @allowJs: true +// @checkJs: true +// @module: commonjs +// @target: es6 +// @filename: file.js +/** + * @namespace myTypes + * @global + * @type {Object} + */ +const myTypes = { + // SOME PROPS HERE +}; + +/** @typedef {string|RegExp|Array} myTypes.typeA */ + +/** + * @typedef myTypes.typeB + * @property {myTypes.typeA} prop1 - Prop 1. + * @property {string} prop2 - Prop 2. + */ + +/** @typedef {myTypes.typeB|Function} myTypes.typeC */ + +exports.myTypes = myTypes; +// @filename: file2.js +const {myTypes} = require('./file.js'); + +/** + * @namespace testFnTypes + * @global + * @type {Object} + */ +const testFnTypes = { + // SOME PROPS HERE +}; + +/** @typedef {boolean|myTypes.typeC} testFnTypes.input */ + +/** + * @function testFn + * @description A test function. + * @param {testFnTypes.input} input - Input. + * @returns {number|null} Result. + */ +function testFn(input) { + if (typeof input === 'number') { + return 2 * input; + } else { + return null; + } +} + +module.exports = {testFn, testFnTypes}; \ No newline at end of file