Skip to content

Commit 5ea4d3b

Browse files
authored
No error for require, module.exports or exports in Javascript (#23743)
* No error for require Still errors for module and exports, and require's type is now incorreclty 'any'; I broke module resolution somehow. Needs investigation. * module/exports symbols+update isCommonJsRequire Everything passes the tests but the code can be improved * Update baselines * Cleanup * Update baselines of new tests * Get rid of exports symbol It wasn't doing anything anyway.
1 parent 5c8bb7c commit 5ea4d3b

21 files changed

+90
-214
lines changed

src/compiler/checker.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ namespace ts {
7575
const undefinedSymbol = createSymbol(SymbolFlags.Property, "undefined" as __String);
7676
undefinedSymbol.declarations = [];
7777
const argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments" as __String);
78+
const requireSymbol = createSymbol(SymbolFlags.Property, "require" as __String);
79+
const moduleSymbol = createSymbol(SymbolFlags.Property, "module" as __String);
7880

7981
/** This will be set during calls to `getResolvedSignature` where services determines an apparent number of arguments greater than what is actually provided. */
8082
let apparentArgumentCount: number | undefined;
@@ -1470,7 +1472,17 @@ namespace ts {
14701472
result = lookup(globals, name, meaning);
14711473
}
14721474
}
1473-
1475+
if (!result) {
1476+
if (originalLocation && isInJavaScriptFile(originalLocation) && originalLocation.parent) {
1477+
if (isRequireCall(originalLocation.parent, /*checkArgumentIsStringLiteralLike*/ false)) {
1478+
return requireSymbol;
1479+
}
1480+
if (isIdentifier(originalLocation) && isPropertyAccessExpression(originalLocation.parent) &&
1481+
originalLocation.escapedText === "module" && originalLocation.parent.name.escapedText === "exports") {
1482+
return moduleSymbol;
1483+
}
1484+
}
1485+
}
14741486
if (!result) {
14751487
if (nameNotFoundMessage) {
14761488
if (!errorLocation ||
@@ -4683,6 +4695,10 @@ namespace ts {
46834695
if (symbol.flags & SymbolFlags.Prototype) {
46844696
return links.type = getTypeOfPrototypeProperty(symbol);
46854697
}
4698+
// CommonsJS require/module/exports all have type any.
4699+
if (symbol === requireSymbol || symbol === moduleSymbol) {
4700+
return links.type = anyType;
4701+
}
46864702
// Handle catch clause variables
46874703
const declaration = symbol.valueDeclaration;
46884704
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
@@ -18856,11 +18872,10 @@ namespace ts {
1885618872
// Make sure require is not a local function
1885718873
if (!isIdentifier(node.expression)) return Debug.fail();
1885818874
const resolvedRequire = resolveName(node.expression, node.expression.escapedText, SymbolFlags.Value, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ true);
18859-
if (!resolvedRequire) {
18860-
// project does not contain symbol named 'require' - assume commonjs require
18875+
if (resolvedRequire === requireSymbol) {
1886118876
return true;
1886218877
}
18863-
// project includes symbol named 'require' - make sure that it it ambient and local non-alias
18878+
// project includes symbol named 'require' - make sure that it is ambient and local non-alias
1886418879
if (resolvedRequire.flags & SymbolFlags.Alias) {
1886518880
return false;
1886618881
}

tests/baselines/reference/dynamicRequire.symbols

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ function foo(name) {
55

66
var s = require("t/" + name)
77
>s : Symbol(s, Decl(a.js, 1, 7))
8+
>require : Symbol(require)
89
>name : Symbol(name, Decl(a.js, 0, 13))
910
}

tests/baselines/reference/exportNestedNamespaces2.errors.txt

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,19 @@
1-
tests/cases/conformance/salsa/first.js(1,11): error TS2304: Cannot find name 'require'.
21
tests/cases/conformance/salsa/first.js(2,9): error TS2339: Property 'formatters' does not exist on type 'typeof import("tests/cases/conformance/salsa/first")'.
3-
tests/cases/conformance/salsa/second.js(1,11): error TS2304: Cannot find name 'require'.
42
tests/cases/conformance/salsa/second.js(2,9): error TS2339: Property 'formatters' does not exist on type 'typeof import("tests/cases/conformance/salsa/second")'.
53

64

75
==== tests/cases/conformance/salsa/mod.js (0 errors) ====
86
// Based on a pattern from adonis
97
exports.formatters = {}
10-
==== tests/cases/conformance/salsa/first.js (2 errors) ====
8+
==== tests/cases/conformance/salsa/first.js (1 errors) ====
119
exports = require('./mod')
12-
~~~~~~~
13-
!!! error TS2304: Cannot find name 'require'.
1410
exports.formatters.j = function (v) {
1511
~~~~~~~~~~
1612
!!! error TS2339: Property 'formatters' does not exist on type 'typeof import("tests/cases/conformance/salsa/first")'.
1713
return v
1814
}
19-
==== tests/cases/conformance/salsa/second.js (2 errors) ====
15+
==== tests/cases/conformance/salsa/second.js (1 errors) ====
2016
exports = require('./mod')
21-
~~~~~~~
22-
!!! error TS2304: Cannot find name 'require'.
2317
exports.formatters.o = function (v) {
2418
~~~~~~~~~~
2519
!!! error TS2339: Property 'formatters' does not exist on type 'typeof import("tests/cases/conformance/salsa/second")'.

tests/baselines/reference/exportNestedNamespaces2.symbols

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ exports.formatters = {}
88
=== tests/cases/conformance/salsa/first.js ===
99
exports = require('./mod')
1010
>exports : Symbol("tests/cases/conformance/salsa/first", Decl(first.js, 0, 0))
11+
>require : Symbol(require)
1112
>'./mod' : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0))
1213

1314
exports.formatters.j = function (v) {
@@ -20,6 +21,7 @@ exports.formatters.j = function (v) {
2021
=== tests/cases/conformance/salsa/second.js ===
2122
exports = require('./mod')
2223
>exports : Symbol("tests/cases/conformance/salsa/second", Decl(second.js, 0, 0))
24+
>require : Symbol(require)
2325
>'./mod' : Symbol("tests/cases/conformance/salsa/mod", Decl(mod.js, 0, 0))
2426

2527
exports.formatters.o = function (v) {

tests/baselines/reference/jsdocReferenceGlobalTypeInCommonJs.errors.txt

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
tests/cases/compiler/a.js(1,15): error TS2304: Cannot find name 'require'.
21
tests/cases/compiler/a.js(4,1): error TS2686: 'Puppeteer' refers to a UMD global, but the current file is a module. Consider adding an import instead.
32

43

5-
==== tests/cases/compiler/a.js (2 errors) ====
4+
==== tests/cases/compiler/a.js (1 errors) ====
65
const other = require('./other');
7-
~~~~~~~
8-
!!! error TS2304: Cannot find name 'require'.
96
/** @type {Puppeteer.Keyboard} */
107
var ppk;
118
Puppeteer.connect;

tests/baselines/reference/jsdocReferenceGlobalTypeInCommonJs.symbols

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
=== tests/cases/compiler/a.js ===
22
const other = require('./other');
33
>other : Symbol(other, Decl(a.js, 0, 5))
4+
>require : Symbol(require)
45
>'./other' : Symbol("tests/cases/compiler/other", Decl(other.d.ts, 0, 0))
56

67
/** @type {Puppeteer.Keyboard} */

tests/baselines/reference/jsdocTypeFromChainedAssignment2.errors.txt

+4-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
tests/cases/conformance/jsdoc/use.js(3,7): error TS2345: Argument of type '"no"' is not assignable to parameter of type 'number'.
2-
tests/cases/conformance/jsdoc/use.js(4,7): error TS2345: Argument of type '"also no"' is not assignable to parameter of type 'number'.
3-
tests/cases/conformance/jsdoc/use.js(5,7): error TS2345: Argument of type '0' is not assignable to parameter of type 'string'.
4-
tests/cases/conformance/jsdoc/use.js(6,7): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
1+
tests/cases/conformance/jsdoc/use.js(2,7): error TS2345: Argument of type '"no"' is not assignable to parameter of type 'number'.
2+
tests/cases/conformance/jsdoc/use.js(3,7): error TS2345: Argument of type '"also no"' is not assignable to parameter of type 'number'.
3+
tests/cases/conformance/jsdoc/use.js(4,7): error TS2345: Argument of type '0' is not assignable to parameter of type 'string'.
4+
tests/cases/conformance/jsdoc/use.js(5,7): error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
55

66

77
==== tests/cases/conformance/jsdoc/use.js (4 errors) ====
8-
/// <reference path='./types.d.ts'/>
98
var mod = require('./mod');
109
mod.f('no')
1110
~~~~
@@ -20,13 +19,7 @@ tests/cases/conformance/jsdoc/use.js(6,7): error TS2345: Argument of type '1' is
2019
~
2120
!!! error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
2221

23-
==== tests/cases/conformance/jsdoc/types.d.ts (0 errors) ====
24-
declare function require(name: string): any;
25-
declare var exports: any;
26-
declare var module: { exports: any };
2722
==== tests/cases/conformance/jsdoc/mod.js (0 errors) ====
28-
/// <reference path='./types.d.ts'/>
29-
3023
/** @param {number} n */
3124
exports.f = exports.g = function fg(n) {
3225
return n + 1
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,56 @@
11
=== tests/cases/conformance/jsdoc/use.js ===
2-
/// <reference path='./types.d.ts'/>
32
var mod = require('./mod');
4-
>mod : Symbol(mod, Decl(use.js, 1, 3))
5-
>require : Symbol(require, Decl(types.d.ts, 0, 0))
3+
>mod : Symbol(mod, Decl(use.js, 0, 3))
4+
>require : Symbol(require)
65
>'./mod' : Symbol("tests/cases/conformance/jsdoc/mod", Decl(mod.js, 0, 0))
76

87
mod.f('no')
98
>mod.f : Symbol(f, Decl(mod.js, 0, 0))
10-
>mod : Symbol(mod, Decl(use.js, 1, 3))
9+
>mod : Symbol(mod, Decl(use.js, 0, 3))
1110
>f : Symbol(f, Decl(mod.js, 0, 0))
1211

1312
mod.g('also no')
14-
>mod.g : Symbol(g, Decl(mod.js, 3, 11))
15-
>mod : Symbol(mod, Decl(use.js, 1, 3))
16-
>g : Symbol(g, Decl(mod.js, 3, 11))
13+
>mod.g : Symbol(g, Decl(mod.js, 1, 11))
14+
>mod : Symbol(mod, Decl(use.js, 0, 3))
15+
>g : Symbol(g, Decl(mod.js, 1, 11))
1716

1817
mod.h(0)
19-
>mod.h : Symbol(h, Decl(mod.js, 5, 1))
20-
>mod : Symbol(mod, Decl(use.js, 1, 3))
21-
>h : Symbol(h, Decl(mod.js, 5, 1))
18+
>mod.h : Symbol(h, Decl(mod.js, 3, 1))
19+
>mod : Symbol(mod, Decl(use.js, 0, 3))
20+
>h : Symbol(h, Decl(mod.js, 3, 1))
2221

2322
mod.i(1)
24-
>mod.i : Symbol(i, Decl(mod.js, 7, 18))
25-
>mod : Symbol(mod, Decl(use.js, 1, 3))
26-
>i : Symbol(i, Decl(mod.js, 7, 18))
27-
28-
=== tests/cases/conformance/jsdoc/types.d.ts ===
29-
declare function require(name: string): any;
30-
>require : Symbol(require, Decl(types.d.ts, 0, 0))
31-
>name : Symbol(name, Decl(types.d.ts, 0, 25))
32-
33-
declare var exports: any;
34-
>exports : Symbol(exports, Decl(types.d.ts, 1, 11))
35-
36-
declare var module: { exports: any };
37-
>module : Symbol(module, Decl(types.d.ts, 2, 11))
38-
>exports : Symbol(exports, Decl(types.d.ts, 2, 21))
23+
>mod.i : Symbol(i, Decl(mod.js, 5, 18))
24+
>mod : Symbol(mod, Decl(use.js, 0, 3))
25+
>i : Symbol(i, Decl(mod.js, 5, 18))
3926

4027
=== tests/cases/conformance/jsdoc/mod.js ===
41-
/// <reference path='./types.d.ts'/>
42-
4328
/** @param {number} n */
4429
exports.f = exports.g = function fg(n) {
4530
>exports.f : Symbol(f, Decl(mod.js, 0, 0))
4631
>exports : Symbol(f, Decl(mod.js, 0, 0))
4732
>f : Symbol(f, Decl(mod.js, 0, 0))
48-
>exports.g : Symbol(g, Decl(mod.js, 3, 11))
49-
>exports : Symbol(g, Decl(mod.js, 3, 11))
50-
>g : Symbol(g, Decl(mod.js, 3, 11))
51-
>fg : Symbol(fg, Decl(mod.js, 3, 23))
52-
>n : Symbol(n, Decl(mod.js, 3, 36))
33+
>exports.g : Symbol(g, Decl(mod.js, 1, 11))
34+
>exports : Symbol(g, Decl(mod.js, 1, 11))
35+
>g : Symbol(g, Decl(mod.js, 1, 11))
36+
>fg : Symbol(fg, Decl(mod.js, 1, 23))
37+
>n : Symbol(n, Decl(mod.js, 1, 36))
5338

5439
return n + 1
55-
>n : Symbol(n, Decl(mod.js, 3, 36))
40+
>n : Symbol(n, Decl(mod.js, 1, 36))
5641
}
5742
/** @param {string} mom */
5843
module.exports.h = module.exports.i = function hi(mom) {
59-
>module.exports : Symbol(h, Decl(mod.js, 5, 1))
60-
>module : Symbol(module, Decl(types.d.ts, 2, 11))
61-
>exports : Symbol(exports, Decl(types.d.ts, 2, 21))
62-
>h : Symbol(h, Decl(mod.js, 5, 1))
63-
>module.exports : Symbol(i, Decl(mod.js, 7, 18))
64-
>module : Symbol(module, Decl(types.d.ts, 2, 11))
65-
>exports : Symbol(exports, Decl(types.d.ts, 2, 21))
66-
>i : Symbol(i, Decl(mod.js, 7, 18))
67-
>hi : Symbol(hi, Decl(mod.js, 7, 37))
68-
>mom : Symbol(mom, Decl(mod.js, 7, 50))
44+
>module.exports : Symbol(h, Decl(mod.js, 3, 1))
45+
>module : Symbol(module)
46+
>h : Symbol(h, Decl(mod.js, 3, 1))
47+
>module.exports : Symbol(i, Decl(mod.js, 5, 18))
48+
>module : Symbol(module)
49+
>i : Symbol(i, Decl(mod.js, 5, 18))
50+
>hi : Symbol(hi, Decl(mod.js, 5, 37))
51+
>mom : Symbol(mom, Decl(mod.js, 5, 50))
6952

7053
return `hi, ${mom}!`;
71-
>mom : Symbol(mom, Decl(mod.js, 7, 50))
54+
>mom : Symbol(mom, Decl(mod.js, 5, 50))
7255
}
7356

tests/baselines/reference/jsdocTypeFromChainedAssignment2.types

+3-18
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
=== tests/cases/conformance/jsdoc/use.js ===
2-
/// <reference path='./types.d.ts'/>
32
var mod = require('./mod');
43
>mod : typeof import("tests/cases/conformance/jsdoc/mod")
54
>require('./mod') : typeof import("tests/cases/conformance/jsdoc/mod")
6-
>require : (name: string) => any
5+
>require : any
76
>'./mod' : "./mod"
87

98
mod.f('no')
@@ -34,21 +33,7 @@ mod.i(1)
3433
>i : (mom: string) => string
3534
>1 : 1
3635

37-
=== tests/cases/conformance/jsdoc/types.d.ts ===
38-
declare function require(name: string): any;
39-
>require : (name: string) => any
40-
>name : string
41-
42-
declare var exports: any;
43-
>exports : any
44-
45-
declare var module: { exports: any };
46-
>module : { exports: any; }
47-
>exports : any
48-
4936
=== tests/cases/conformance/jsdoc/mod.js ===
50-
/// <reference path='./types.d.ts'/>
51-
5237
/** @param {number} n */
5338
exports.f = exports.g = function fg(n) {
5439
>exports.f = exports.g = function fg(n) { return n + 1} : (n: number) => number
@@ -73,13 +58,13 @@ module.exports.h = module.exports.i = function hi(mom) {
7358
>module.exports.h = module.exports.i = function hi(mom) { return `hi, ${mom}!`;} : (mom: string) => string
7459
>module.exports.h : any
7560
>module.exports : any
76-
>module : { exports: any; }
61+
>module : any
7762
>exports : any
7863
>h : any
7964
>module.exports.i = function hi(mom) { return `hi, ${mom}!`;} : (mom: string) => string
8065
>module.exports.i : any
8166
>module.exports : any
82-
>module : { exports: any; }
67+
>module : any
8368
>exports : any
8469
>i : any
8570
>function hi(mom) { return `hi, ${mom}!`;} : (mom: string) => string

0 commit comments

Comments
 (0)