diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 1003b23b455..047320c67a4 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2974,6 +2974,10 @@ namespace ts { if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) { return; } + const rootExpr = getLeftmostAccessExpression(node.left); + if (isIdentifier(rootExpr) && lookupSymbolForName(container, rootExpr.escapedText)!?.flags & SymbolFlags.Alias) { + return; + } // Fix up parent pointers since we're going to use these nodes before we bind into them setParent(node.left, node); setParent(node.right, node); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 441e75ded31..17ed538452c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2416,7 +2416,7 @@ namespace ts { function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration | VariableDeclaration, dontResolveAlias: boolean): Symbol | undefined { if (isVariableDeclaration(node) && node.initializer && isPropertyAccessExpression(node.initializer)) { - const name = (getLeftmostPropertyAccessExpression(node.initializer.expression) as CallExpression).arguments[0] as StringLiteral; + const name = (getLeftmostAccessExpression(node.initializer.expression) as CallExpression).arguments[0] as StringLiteral; return isIdentifier(node.initializer.name) ? resolveSymbol(getPropertyOfType(resolveExternalModuleTypeByLiteral(name), node.initializer.name.escapedText)) : undefined; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2653036ba9e..dbe93a214d1 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1869,7 +1869,7 @@ namespace ts { export function getExternalModuleRequireArgument(node: Node) { return isRequireVariableDeclaration(node, /*requireStringLiteralLikeArgument*/ true) - && (getLeftmostPropertyAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral; + && (getLeftmostAccessExpression(node.initializer) as CallExpression).arguments[0] as StringLiteral; } export function isInternalModuleImportEqualsDeclaration(node: Node): node is ImportEqualsDeclaration { @@ -1940,7 +1940,7 @@ namespace ts { export function isRequireVariableDeclaration(node: Node, requireStringLiteralLikeArgument: boolean): node is VariableDeclaration; export function isRequireVariableDeclaration(node: Node, requireStringLiteralLikeArgument: boolean): node is VariableDeclaration { node = getRootDeclaration(node); - return isVariableDeclaration(node) && !!node.initializer && isRequireCall(getLeftmostPropertyAccessExpression(node.initializer), requireStringLiteralLikeArgument); + return isVariableDeclaration(node) && !!node.initializer && isRequireCall(getLeftmostAccessExpression(node.initializer), requireStringLiteralLikeArgument); } export function isRequireVariableStatement(node: Node, requireStringLiteralLikeArgument = true): node is RequireVariableStatement { @@ -5463,8 +5463,8 @@ namespace ts { return node.kind === SyntaxKind.NamedImports || node.kind === SyntaxKind.NamedExports; } - export function getLeftmostPropertyAccessExpression(expr: Expression): Expression { - while (isPropertyAccessExpression(expr)) { + export function getLeftmostAccessExpression(expr: Expression): Expression { + while (isAccessExpression(expr)) { expr = expr.expression; } return expr; diff --git a/tests/baselines/reference/namespaceAssignmentToRequireAlias.errors.txt b/tests/baselines/reference/namespaceAssignmentToRequireAlias.errors.txt new file mode 100644 index 00000000000..56b144db422 --- /dev/null +++ b/tests/baselines/reference/namespaceAssignmentToRequireAlias.errors.txt @@ -0,0 +1,14 @@ +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. + + +==== tests/cases/conformance/salsa/bug40140.js (1 errors) ==== + const u = require('untyped'); + ~~~~~~~~~ +!!! 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. + u.assignment.nested = true + u.noError() + + +==== tests/cases/conformance/salsa/node_modules/untyped/index.js (0 errors) ==== + module.exports = {} + \ No newline at end of file diff --git a/tests/baselines/reference/namespaceAssignmentToRequireAlias.js b/tests/baselines/reference/namespaceAssignmentToRequireAlias.js new file mode 100644 index 00000000000..a7b48d97325 --- /dev/null +++ b/tests/baselines/reference/namespaceAssignmentToRequireAlias.js @@ -0,0 +1,21 @@ +//// [tests/cases/conformance/salsa/namespaceAssignmentToRequireAlias.ts] //// + +//// [index.js] +module.exports = {} + +//// [bug40140.js] +const u = require('untyped'); +u.assignment.nested = true +u.noError() + + + +//// [bug40140.js] +"use strict"; +var u = require('untyped'); +u.assignment.nested = true; +u.noError(); + + +//// [bug40140.d.ts] +export {}; diff --git a/tests/baselines/reference/namespaceAssignmentToRequireAlias.symbols b/tests/baselines/reference/namespaceAssignmentToRequireAlias.symbols new file mode 100644 index 00000000000..b702e7e7665 --- /dev/null +++ b/tests/baselines/reference/namespaceAssignmentToRequireAlias.symbols @@ -0,0 +1,12 @@ +=== tests/cases/conformance/salsa/bug40140.js === +const u = require('untyped'); +>u : Symbol(u, Decl(bug40140.js, 0, 5)) +>require : Symbol(require) + +u.assignment.nested = true +>u : Symbol(u, Decl(bug40140.js, 0, 5)) + +u.noError() +>u : Symbol(u, Decl(bug40140.js, 0, 5)) + + diff --git a/tests/baselines/reference/namespaceAssignmentToRequireAlias.types b/tests/baselines/reference/namespaceAssignmentToRequireAlias.types new file mode 100644 index 00000000000..7af717585fc --- /dev/null +++ b/tests/baselines/reference/namespaceAssignmentToRequireAlias.types @@ -0,0 +1,23 @@ +=== tests/cases/conformance/salsa/bug40140.js === +const u = require('untyped'); +>u : any +>require('untyped') : any +>require : any +>'untyped' : "untyped" + +u.assignment.nested = true +>u.assignment.nested = true : true +>u.assignment.nested : any +>u.assignment : any +>u : any +>assignment : any +>nested : any +>true : true + +u.noError() +>u.noError() : any +>u.noError : any +>u : any +>noError : any + + diff --git a/tests/cases/conformance/salsa/namespaceAssignmentToRequireAlias.ts b/tests/cases/conformance/salsa/namespaceAssignmentToRequireAlias.ts new file mode 100644 index 00000000000..fc814e5cdb5 --- /dev/null +++ b/tests/cases/conformance/salsa/namespaceAssignmentToRequireAlias.ts @@ -0,0 +1,13 @@ +// @allowJs: true +// @checkJs: true +// @strict: true +// @outDir: out +// @declaration: true +// @filename: node_modules/untyped/index.js +module.exports = {} + +// @filename: bug40140.js +const u = require('untyped'); +u.assignment.nested = true +u.noError() +