diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 19b9389bf0ccb..28c2fc89b3792 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2049,6 +2049,18 @@ namespace ts { if (initializer) { namespace = getSymbolOfNode(initializer); } + if (namespace.valueDeclaration && + isVariableDeclaration(namespace.valueDeclaration) && + isCommonJsRequire(namespace.valueDeclaration.initializer)) { + const moduleName = (namespace.valueDeclaration.initializer as CallExpression).arguments[0] as StringLiteral; + const moduleSym = resolveExternalModuleName(moduleName, moduleName); + if (moduleSym) { + const resolvedModuleSymbol = resolveExternalModuleSymbol(moduleSym); + if (resolvedModuleSymbol) { + namespace = resolvedModuleSymbol; + } + } + } } symbol = getSymbol(getExportsOfSymbol(namespace), right.escapedText, meaning); if (!symbol) { @@ -18133,7 +18145,7 @@ namespace ts { // In JavaScript files, calls to any identifier 'require' are treated as external module imports if (isInJavaScriptFile(node) && isCommonJsRequire(node)) { - return resolveExternalModuleTypeByLiteral(node.arguments[0]); + return resolveExternalModuleTypeByLiteral(node.arguments[0] as StringLiteral); } const returnType = getReturnTypeOfSignature(signature); diff --git a/tests/baselines/reference/varRequireFromJavascript.errors.txt b/tests/baselines/reference/varRequireFromJavascript.errors.txt new file mode 100644 index 0000000000000..29b1afe34205c --- /dev/null +++ b/tests/baselines/reference/varRequireFromJavascript.errors.txt @@ -0,0 +1,32 @@ +tests/cases/conformance/salsa/use.js(1,10): error TS2304: Cannot find name 'require'. + + +==== tests/cases/conformance/salsa/use.js (1 errors) ==== + var ex = require('./ex') + ~~~~~~~ +!!! error TS2304: Cannot find name 'require'. + + // values work + var crunch = new ex.Crunch(1); + crunch.n + + + // types work + /** + * @param {ex.Crunch} wrap + */ + function f(wrap) { + wrap.n + } + +==== tests/cases/conformance/salsa/ex.js (0 errors) ==== + export class Crunch { + /** @param {number} n */ + constructor(n) { + this.n = n + } + m() { + return this.n + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/varRequireFromJavascript.symbols b/tests/baselines/reference/varRequireFromJavascript.symbols new file mode 100644 index 0000000000000..e892ed6bcb9fe --- /dev/null +++ b/tests/baselines/reference/varRequireFromJavascript.symbols @@ -0,0 +1,56 @@ +=== tests/cases/conformance/salsa/use.js === +var ex = require('./ex') +>ex : Symbol(ex, Decl(use.js, 0, 3)) +>'./ex' : Symbol("tests/cases/conformance/salsa/ex", Decl(ex.js, 0, 0)) + +// values work +var crunch = new ex.Crunch(1); +>crunch : Symbol(crunch, Decl(use.js, 3, 3)) +>ex.Crunch : Symbol(Crunch, Decl(ex.js, 0, 0)) +>ex : Symbol(ex, Decl(use.js, 0, 3)) +>Crunch : Symbol(Crunch, Decl(ex.js, 0, 0)) + +crunch.n +>crunch.n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) +>crunch : Symbol(crunch, Decl(use.js, 3, 3)) +>n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) + + +// types work +/** + * @param {ex.Crunch} wrap + */ +function f(wrap) { +>f : Symbol(f, Decl(use.js, 4, 8)) +>wrap : Symbol(wrap, Decl(use.js, 11, 11)) + + wrap.n +>wrap.n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) +>wrap : Symbol(wrap, Decl(use.js, 11, 11)) +>n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) +} + +=== tests/cases/conformance/salsa/ex.js === +export class Crunch { +>Crunch : Symbol(Crunch, Decl(ex.js, 0, 0)) + + /** @param {number} n */ + constructor(n) { +>n : Symbol(n, Decl(ex.js, 2, 16)) + + this.n = n +>this.n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) +>this : Symbol(Crunch, Decl(ex.js, 0, 0)) +>n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) +>n : Symbol(n, Decl(ex.js, 2, 16)) + } + m() { +>m : Symbol(Crunch.m, Decl(ex.js, 4, 5)) + + return this.n +>this.n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) +>this : Symbol(Crunch, Decl(ex.js, 0, 0)) +>n : Symbol(Crunch.n, Decl(ex.js, 2, 20)) + } +} + diff --git a/tests/baselines/reference/varRequireFromJavascript.types b/tests/baselines/reference/varRequireFromJavascript.types new file mode 100644 index 0000000000000..b17cc3f6f3b08 --- /dev/null +++ b/tests/baselines/reference/varRequireFromJavascript.types @@ -0,0 +1,61 @@ +=== tests/cases/conformance/salsa/use.js === +var ex = require('./ex') +>ex : typeof "tests/cases/conformance/salsa/ex" +>require('./ex') : typeof "tests/cases/conformance/salsa/ex" +>require : any +>'./ex' : "./ex" + +// values work +var crunch = new ex.Crunch(1); +>crunch : Crunch +>new ex.Crunch(1) : Crunch +>ex.Crunch : typeof Crunch +>ex : typeof "tests/cases/conformance/salsa/ex" +>Crunch : typeof Crunch +>1 : 1 + +crunch.n +>crunch.n : number +>crunch : Crunch +>n : number + + +// types work +/** + * @param {ex.Crunch} wrap + */ +function f(wrap) { +>f : (wrap: Crunch) => void +>wrap : Crunch + + wrap.n +>wrap.n : number +>wrap : Crunch +>n : number +} + +=== tests/cases/conformance/salsa/ex.js === +export class Crunch { +>Crunch : Crunch + + /** @param {number} n */ + constructor(n) { +>n : number + + this.n = n +>this.n = n : number +>this.n : number +>this : this +>n : number +>n : number + } + m() { +>m : () => number + + return this.n +>this.n : number +>this : this +>n : number + } +} + diff --git a/tests/baselines/reference/varRequireFromTypescript.errors.txt b/tests/baselines/reference/varRequireFromTypescript.errors.txt new file mode 100644 index 0000000000000..39172d6f33d33 --- /dev/null +++ b/tests/baselines/reference/varRequireFromTypescript.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/salsa/use.js(1,10): error TS2304: Cannot find name 'require'. + + +==== tests/cases/conformance/salsa/use.js (1 errors) ==== + var ex = require('./ex') + ~~~~~~~ +!!! error TS2304: Cannot find name 'require'. + + // values work + var crunch = new ex.Crunch(1); + crunch.n + + + // types work + /** + * @param {ex.Greatest} greatest + * @param {ex.Crunch} wrap + */ + function f(greatest, wrap) { + greatest.day + wrap.n + } + +==== tests/cases/conformance/salsa/ex.d.ts (0 errors) ==== + export type Greatest = { day: 1 } + export class Crunch { + n: number + m(): number + constructor(n: number) + } + \ No newline at end of file diff --git a/tests/baselines/reference/varRequireFromTypescript.symbols b/tests/baselines/reference/varRequireFromTypescript.symbols new file mode 100644 index 0000000000000..f8e1223c46e46 --- /dev/null +++ b/tests/baselines/reference/varRequireFromTypescript.symbols @@ -0,0 +1,57 @@ +=== tests/cases/conformance/salsa/use.js === +var ex = require('./ex') +>ex : Symbol(ex, Decl(use.js, 0, 3)) +>'./ex' : Symbol("tests/cases/conformance/salsa/ex", Decl(ex.d.ts, 0, 0)) + +// values work +var crunch = new ex.Crunch(1); +>crunch : Symbol(crunch, Decl(use.js, 3, 3)) +>ex.Crunch : Symbol(Crunch, Decl(ex.d.ts, 0, 33)) +>ex : Symbol(ex, Decl(use.js, 0, 3)) +>Crunch : Symbol(Crunch, Decl(ex.d.ts, 0, 33)) + +crunch.n +>crunch.n : Symbol(Crunch.n, Decl(ex.d.ts, 1, 21)) +>crunch : Symbol(crunch, Decl(use.js, 3, 3)) +>n : Symbol(Crunch.n, Decl(ex.d.ts, 1, 21)) + + +// types work +/** + * @param {ex.Greatest} greatest + * @param {ex.Crunch} wrap + */ +function f(greatest, wrap) { +>f : Symbol(f, Decl(use.js, 4, 8)) +>greatest : Symbol(greatest, Decl(use.js, 12, 11)) +>wrap : Symbol(wrap, Decl(use.js, 12, 20)) + + greatest.day +>greatest.day : Symbol(day, Decl(ex.d.ts, 0, 24)) +>greatest : Symbol(greatest, Decl(use.js, 12, 11)) +>day : Symbol(day, Decl(ex.d.ts, 0, 24)) + + wrap.n +>wrap.n : Symbol(Crunch.n, Decl(ex.d.ts, 1, 21)) +>wrap : Symbol(wrap, Decl(use.js, 12, 20)) +>n : Symbol(Crunch.n, Decl(ex.d.ts, 1, 21)) +} + +=== tests/cases/conformance/salsa/ex.d.ts === +export type Greatest = { day: 1 } +>Greatest : Symbol(Greatest, Decl(ex.d.ts, 0, 0)) +>day : Symbol(day, Decl(ex.d.ts, 0, 24)) + +export class Crunch { +>Crunch : Symbol(Crunch, Decl(ex.d.ts, 0, 33)) + + n: number +>n : Symbol(Crunch.n, Decl(ex.d.ts, 1, 21)) + + m(): number +>m : Symbol(Crunch.m, Decl(ex.d.ts, 2, 13)) + + constructor(n: number) +>n : Symbol(n, Decl(ex.d.ts, 4, 16)) +} + diff --git a/tests/baselines/reference/varRequireFromTypescript.types b/tests/baselines/reference/varRequireFromTypescript.types new file mode 100644 index 0000000000000..78f0790239e78 --- /dev/null +++ b/tests/baselines/reference/varRequireFromTypescript.types @@ -0,0 +1,61 @@ +=== tests/cases/conformance/salsa/use.js === +var ex = require('./ex') +>ex : typeof "tests/cases/conformance/salsa/ex" +>require('./ex') : typeof "tests/cases/conformance/salsa/ex" +>require : any +>'./ex' : "./ex" + +// values work +var crunch = new ex.Crunch(1); +>crunch : Crunch +>new ex.Crunch(1) : Crunch +>ex.Crunch : typeof Crunch +>ex : typeof "tests/cases/conformance/salsa/ex" +>Crunch : typeof Crunch +>1 : 1 + +crunch.n +>crunch.n : number +>crunch : Crunch +>n : number + + +// types work +/** + * @param {ex.Greatest} greatest + * @param {ex.Crunch} wrap + */ +function f(greatest, wrap) { +>f : (greatest: { day: 1; }, wrap: Crunch) => void +>greatest : { day: 1; } +>wrap : Crunch + + greatest.day +>greatest.day : 1 +>greatest : { day: 1; } +>day : 1 + + wrap.n +>wrap.n : number +>wrap : Crunch +>n : number +} + +=== tests/cases/conformance/salsa/ex.d.ts === +export type Greatest = { day: 1 } +>Greatest : Greatest +>day : 1 + +export class Crunch { +>Crunch : Crunch + + n: number +>n : number + + m(): number +>m : () => number + + constructor(n: number) +>n : number +} + diff --git a/tests/cases/conformance/salsa/varRequireFromJavascript.ts b/tests/cases/conformance/salsa/varRequireFromJavascript.ts new file mode 100644 index 0000000000000..2ae340a5e70e4 --- /dev/null +++ b/tests/cases/conformance/salsa/varRequireFromJavascript.ts @@ -0,0 +1,30 @@ +// @allowJs: true +// @checkJs: true +// @strict: true +// @noEmit: true +// @Filename: ex.js +export class Crunch { + /** @param {number} n */ + constructor(n) { + this.n = n + } + m() { + return this.n + } +} + +// @Filename: use.js +var ex = require('./ex') + +// values work +var crunch = new ex.Crunch(1); +crunch.n + + +// types work +/** + * @param {ex.Crunch} wrap + */ +function f(wrap) { + wrap.n +} diff --git a/tests/cases/conformance/salsa/varRequireFromTypescript.ts b/tests/cases/conformance/salsa/varRequireFromTypescript.ts new file mode 100644 index 0000000000000..c46d0c5a87e1c --- /dev/null +++ b/tests/cases/conformance/salsa/varRequireFromTypescript.ts @@ -0,0 +1,29 @@ +// @allowJs: true +// @checkJs: true +// @strict: true +// @noEmit: true +// @Filename: ex.d.ts +export type Greatest = { day: 1 } +export class Crunch { + n: number + m(): number + constructor(n: number) +} + +// @Filename: use.js +var ex = require('./ex') + +// values work +var crunch = new ex.Crunch(1); +crunch.n + + +// types work +/** + * @param {ex.Greatest} greatest + * @param {ex.Crunch} wrap + */ +function f(greatest, wrap) { + greatest.day + wrap.n +}