Skip to content

Commit 378083f

Browse files
authored
Nested assignment to a require alias isn't a declaration (microsoft#40186)
This is not something we can type correctly, and doesn't work in Typescript either. Better to ignore it in JS.
1 parent 5fd5a75 commit 378083f

8 files changed

+92
-5
lines changed

src/compiler/binder.ts

+4
Original file line numberDiff line numberDiff line change
@@ -2974,6 +2974,10 @@ namespace ts {
29742974
if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) {
29752975
return;
29762976
}
2977+
const rootExpr = getLeftmostAccessExpression(node.left);
2978+
if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)!?.flags & SymbolFlags.Alias) {
2979+
return;
2980+
}
29772981
// Fix up parent pointers since we're going to use these nodes before we bind into them
29782982
setParent(node.left, node);
29792983
setParent(node.right, node);

src/compiler/checker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2416,7 +2416,7 @@ namespace ts {
24162416

24172417
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration | VariableDeclaration, dontResolveAlias: boolean): Symbol | undefined {
24182418
if (isVariableDeclaration(node) && node.initializer && isPropertyAccessExpression(node.initializer)) {
2419-
const name = (getLeftmostPropertyAccessExpression(node.initializer.expression) as CallExpression).arguments[0] as StringLiteral;
2419+
const name = (getLeftmostAccessExpression(node.initializer.expression) as CallExpression).arguments[0] as StringLiteral;
24202420
return isIdentifier(node.initializer.name)
24212421
? resolveSymbol(getPropertyOfType(resolveExternalModuleTypeByLiteral(name), node.initializer.name.escapedText))
24222422
: undefined;

src/compiler/utilities.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -1869,7 +1869,7 @@ namespace ts {
18691869

18701870
export function getExternalModuleRequireArgument(node: Node) {
18711871
return isRequireVariableDeclaration(node, /*requireStringLiteralLikeArgument*/ true)
1872-
&& (getLeftmostPropertyAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral;
1872+
&& (getLeftmostAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral;
18731873
}
18741874

18751875
export function isInternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration {
@@ -1940,7 +1940,7 @@ namespace ts {
19401940
export function isRequireVariableDeclaration(node: Node, requireStringLiteralLikeArgument: boolean): node is VariableDeclaration;
19411941
export function isRequireVariableDeclaration(node: Node, requireStringLiteralLikeArgument: boolean): node is VariableDeclaration {
19421942
node = getRootDeclaration(node);
1943-
return isVariableDeclaration(node) && !!node.initializer && isRequireCall(getLeftmostPropertyAccessExpression(node.initializer), requireStringLiteralLikeArgument);
1943+
return isVariableDeclaration(node) && !!node.initializer && isRequireCall(getLeftmostAccessExpression(node.initializer), requireStringLiteralLikeArgument);
19441944
}
19451945

19461946
export function isRequireVariableStatement(node: Node, requireStringLiteralLikeArgument = true): node is RequireVariableStatement {
@@ -5463,8 +5463,8 @@ namespace ts {
54635463
return node.kind === SyntaxKind.NamedImports || node.kind === SyntaxKind.NamedExports;
54645464
}
54655465

5466-
export function getLeftmostPropertyAccessExpression(expr: Expression): Expression {
5467-
while (isPropertyAccessExpression(expr)) {
5466+
export function getLeftmostAccessExpression(expr: Expression): Expression {
5467+
while (isAccessExpression(expr)) {
54685468
expr = expr.expression;
54695469
}
54705470
return expr;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
tests/cases/conformance/salsa/bug40140.js(1,19): error TS7016: Could not find a declaration file for module 'untyped'. 'tests/cases/conformance/salsa/node_modules/untyped/index.js' implicitly has an 'any' type.
2+
3+
4+
==== tests/cases/conformance/salsa/bug40140.js (1 errors) ====
5+
const u = require('untyped');
6+
~~~~~~~~~
7+
!!! error TS7016: Could not find a declaration file for module 'untyped'. 'tests/cases/conformance/salsa/node_modules/untyped/index.js' implicitly has an 'any' type.
8+
u.assignment.nested = true
9+
u.noError()
10+
11+
12+
==== tests/cases/conformance/salsa/node_modules/untyped/index.js (0 errors) ====
13+
module.exports = {}
14+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [tests/cases/conformance/salsa/namespaceAssignmentToRequireAlias.ts] ////
2+
3+
//// [index.js]
4+
module.exports = {}
5+
6+
//// [bug40140.js]
7+
const u = require('untyped');
8+
u.assignment.nested = true
9+
u.noError()
10+
11+
12+
13+
//// [bug40140.js]
14+
"use strict";
15+
var u = require('untyped');
16+
u.assignment.nested = true;
17+
u.noError();
18+
19+
20+
//// [bug40140.d.ts]
21+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== tests/cases/conformance/salsa/bug40140.js ===
2+
const u = require('untyped');
3+
>u : Symbol(u, Decl(bug40140.js, 0, 5))
4+
>require : Symbol(require)
5+
6+
u.assignment.nested = true
7+
>u : Symbol(u, Decl(bug40140.js, 0, 5))
8+
9+
u.noError()
10+
>u : Symbol(u, Decl(bug40140.js, 0, 5))
11+
12+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/conformance/salsa/bug40140.js ===
2+
const u = require('untyped');
3+
>u : any
4+
>require('untyped') : any
5+
>require : any
6+
>'untyped' : "untyped"
7+
8+
u.assignment.nested = true
9+
>u.assignment.nested = true : true
10+
>u.assignment.nested : any
11+
>u.assignment : any
12+
>u : any
13+
>assignment : any
14+
>nested : any
15+
>true : true
16+
17+
u.noError()
18+
>u.noError() : any
19+
>u.noError : any
20+
>u : any
21+
>noError : any
22+
23+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// @allowJs: true
2+
// @checkJs: true
3+
// @strict: true
4+
// @outDir: out
5+
// @declaration: true
6+
// @filename: node_modules/untyped/index.js
7+
module.exports = {}
8+
9+
// @filename: bug40140.js
10+
const u = require('untyped');
11+
u.assignment.nested = true
12+
u.noError()
13+

0 commit comments

Comments
 (0)