diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index e717efa5dba70..4e84cf197ad19 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2336,7 +2336,7 @@ namespace ts { // For `f.prototype.m = function() { this.x = 0; }`, `this.x = 0` should modify `f`'s members, not the function expression. if (isBinaryExpression(thisContainer.parent) && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken) { const l = thisContainer.parent.left; - if (isPropertyAccessExpression(l) && isPropertyAccessExpression(l.expression) && l.expression.name.escapedText === "prototype" && isEntityNameExpression(l.expression.expression)) { + if (isPropertyAccessEntityNameExpression(l) && isPrototypeAccess(l.expression)) { constructorSymbol = getJSInitializerSymbolFromName(l.expression.expression, containerContainer); } } @@ -2368,12 +2368,12 @@ namespace ts { if (node.expression.kind === SyntaxKind.ThisKeyword) { bindThisPropertyAssignment(node); } - else if (isEntityNameExpression(node) && node.parent.parent.kind === SyntaxKind.SourceFile) { - if (isPropertyAccessExpression(node.expression) && node.expression.name.escapedText === "prototype") { - bindPrototypePropertyAssignment(node as PropertyAccessEntityNameExpression, node.parent); + else if (isPropertyAccessEntityNameExpression(node) && node.parent.parent.kind === SyntaxKind.SourceFile) { + if (isPrototypeAccess(node.expression)) { + bindPrototypePropertyAssignment(node, node.parent); } else { - bindStaticPropertyAssignment(node as PropertyAccessEntityNameExpression); + bindStaticPropertyAssignment(node); } } } @@ -2436,15 +2436,10 @@ namespace ts { function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) { let symbol = getJSInitializerSymbolFromName(name); - let isToplevelNamespaceableInitializer: boolean; - if (isBinaryExpression(propertyAccess.parent)) { - const isPrototypeAssignment = isPropertyAccessExpression(propertyAccess.parent.left) && propertyAccess.parent.left.name.escapedText === "prototype"; - isToplevelNamespaceableInitializer = propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile && - !!getJavascriptInitializer(propertyAccess.parent.right, isPrototypeAssignment); - } - else { - isToplevelNamespaceableInitializer = propertyAccess.parent.parent.kind === SyntaxKind.SourceFile; - } + const isToplevelNamespaceableInitializer = isBinaryExpression(propertyAccess.parent) + ? propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile && + !!getJavascriptInitializer(propertyAccess.parent.right, isPrototypeAccess(propertyAccess.parent.left)) + : propertyAccess.parent.parent.kind === SyntaxKind.SourceFile; if (!isPrototypeProperty && (!symbol || !(symbol.flags & SymbolFlags.Namespace)) && isToplevelNamespaceableInitializer) { // make symbols or add declarations for intermediate containers const flags = SymbolFlags.Module | SymbolFlags.JSContainer; diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2dcea191b5493..629ce86c9b67e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -18069,8 +18069,7 @@ namespace ts { parent = parent.parent; } return parent && isBinaryExpression(parent) && - isPropertyAccessExpression(parent.left) && - parent.left.name.escapedText === "prototype" && + isPrototypeAccess(parent.left) && parent.operatorToken.kind === SyntaxKind.EqualsToken && isObjectLiteralExpression(parent.right) && parent.right; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 4077d33933e11..60b140adacecb 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1509,7 +1509,7 @@ namespace ts { */ export function getAssignedJavascriptInitializer(node: Node) { if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) { - const isPrototypeAssignment = isPropertyAccessExpression(node.parent.left) && node.parent.left.name.escapedText === "prototype"; + const isPrototypeAssignment = isPrototypeAccess(node.parent.left); return getJavascriptInitializer(node.parent.right, isPrototypeAssignment) || getDefaultedJavascriptInitializer(node.parent.left as EntityNameExpression, node.parent.right, isPrototypeAssignment); } @@ -1629,7 +1629,7 @@ namespace ts { // F.prototype = { ... } return SpecialPropertyAssignmentKind.Prototype; } - else if (isPropertyAccessExpression(lhs.expression) && lhs.expression.name.escapedText === "prototype") { + else if (isPrototypeAccess(lhs.expression)) { // F.G....prototype.x = expr return SpecialPropertyAssignmentKind.PrototypeProperty; } @@ -3336,8 +3336,15 @@ namespace ts { } export function isEntityNameExpression(node: Node): node is EntityNameExpression { - return node.kind === SyntaxKind.Identifier || - node.kind === SyntaxKind.PropertyAccessExpression && isEntityNameExpression((node).expression); + return node.kind === SyntaxKind.Identifier || isPropertyAccessEntityNameExpression(node); + } + + export function isPropertyAccessEntityNameExpression(node: Node): node is PropertyAccessEntityNameExpression { + return isPropertyAccessExpression(node) && isEntityNameExpression(node.expression); + } + + export function isPrototypeAccess(node: Node): node is PropertyAccessExpression { + return isPropertyAccessExpression(node) && node.name.escapedText === "prototype"; } export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {