From 249f925c93cfb390c990510384f0d88ab394b80a Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 29 Jul 2020 12:49:29 -0700 Subject: [PATCH 1/3] Make direct assignments to cjs exports considered literal contexts --- src/compiler/checker.ts | 13 ++-- src/compiler/utilities.ts | 17 ++++- .../reference/assignmentToVoidZero1.js | 4 +- .../reference/assignmentToVoidZero1.types | 16 ++--- .../reference/assignmentToVoidZero2.js | 2 +- .../reference/assignmentToVoidZero2.types | 8 +-- .../reference/commonJsUnusedLocals.types | 4 +- .../reference/commonjsAccessExports.types | 8 +-- .../jsDeclarationsCrossfileMerge.types | 8 +-- .../jsExportAssignmentNonMutableLocation.js | 15 +++++ ...ExportAssignmentNonMutableLocation.symbols | 22 +++++++ ...jsExportAssignmentNonMutableLocation.types | 29 +++++++++ ...tMemberMergedWithModuleAugmentation3.types | 4 +- ...sFileCompilationExternalPackageError.types | 4 +- .../reference/moduleExportAlias5.types | 18 +++--- .../reference/moduleExportAliasExports.types | 8 +-- .../reference/moduleExportAliasImported.types | 6 +- .../reference/moduleExportAssignment.types | 8 +-- ...rtWithExportPropertyAssignment3.errors.txt | 16 ++--- ...eExportWithExportPropertyAssignment3.types | 62 +++++++++---------- ...rtWithExportPropertyAssignment4.errors.txt | 16 ++--- ...eExportWithExportPropertyAssignment4.types | 32 +++++----- ...Resolution_explicitNodeModulesImport.types | 6 +- .../reference/typedefCrossModule2.types | 30 ++++----- .../jsExportAssignmentNonMutableLocation.ts | 15 +++++ 25 files changed, 233 insertions(+), 138 deletions(-) create mode 100644 tests/baselines/reference/jsExportAssignmentNonMutableLocation.js create mode 100644 tests/baselines/reference/jsExportAssignmentNonMutableLocation.symbols create mode 100644 tests/baselines/reference/jsExportAssignmentNonMutableLocation.types create mode 100644 tests/cases/compiler/jsExportAssignmentNonMutableLocation.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5c31002cf2773..6218e46c04246 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8069,7 +8069,8 @@ namespace ts { if (containsSameNamedThisProperty(expression.left, expression.right)) { return anyType; } - const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) : getWidenedLiteralType(checkExpressionCached(expression.right)); + const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); + const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) : (isDirectExport ? getRegularTypeOfLiteralType : getWidenedLiteralType)(checkExpressionCached(expression.right)); if (type.flags & TypeFlags.Object && kind === AssignmentDeclarationKind.ModuleExports && symbol.escapedName === InternalSymbolName.ExportEquals) { @@ -14265,9 +14266,11 @@ namespace ts { function getESSymbolLikeTypeForNode(node: Node) { if (isValidESSymbolDeclaration(node)) { - const symbol = getSymbolOfNode(node); - const links = getSymbolLinks(symbol); - return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol)); + const symbol = isCommonJsExportPropertyAssignment(node) ? getSymbolOfNode((node as BinaryExpression).left) : getSymbolOfNode(node); + if (symbol) { + const links = getSymbolLinks(symbol); + return links.uniqueESSymbolType || (links.uniqueESSymbolType = createUniqueESSymbolType(symbol)); + } } return esSymbolType; } @@ -29886,7 +29889,7 @@ namespace ts { function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type { const type = checkExpression(node, checkMode, forceTuple); - return isConstContext(node) ? getRegularTypeOfLiteralType(type) : + return isConstContext(node) || isCommonJsExportedExpresion(node) ? getRegularTypeOfLiteralType(type) : isTypeAssertion(node) ? type : getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node) : contextualType, node)); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 41d513a252303..383b5484713ec 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1345,10 +1345,21 @@ namespace ts { && node.parent.parent.kind === SyntaxKind.VariableStatement; } - export function isValidESSymbolDeclaration(node: Node): node is VariableDeclaration | PropertyDeclaration | SignatureDeclaration { - return isVariableDeclaration(node) ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) : + export function isCommonJsExportedExpresion(node: Node) { + if (!isInJSFile(node)) return false; + return (isObjectLiteralExpression(node.parent) && isBinaryExpression(node.parent.parent) && getAssignmentDeclarationKind(node.parent.parent) === AssignmentDeclarationKind.ModuleExports) || + isCommonJsExportPropertyAssignment(node.parent); + } + + export function isCommonJsExportPropertyAssignment(node: Node) { + if (!isInJSFile(node)) return false; + return (isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ExportsProperty); + } + + export function isValidESSymbolDeclaration(node: Node): boolean { + return (isVariableDeclaration(node) ? isVarConst(node) && isIdentifier(node.name) && isVariableDeclarationInVariableStatement(node) : isPropertyDeclaration(node) ? hasEffectiveReadonlyModifier(node) && hasStaticModifier(node) : - isPropertySignature(node) && hasEffectiveReadonlyModifier(node); + isPropertySignature(node) && hasEffectiveReadonlyModifier(node)) || isCommonJsExportPropertyAssignment(node); } export function introducesArgumentsExoticObject(node: Node) { diff --git a/tests/baselines/reference/assignmentToVoidZero1.js b/tests/baselines/reference/assignmentToVoidZero1.js index 542c1fdcf1818..1ab9bb516070e 100644 --- a/tests/baselines/reference/assignmentToVoidZero1.js +++ b/tests/baselines/reference/assignmentToVoidZero1.js @@ -13,5 +13,5 @@ exports.y = 2; //// [assignmentToVoidZero1.d.ts] -export var x: number; -export var y: number; +export var x: 1; +export var y: 2; diff --git a/tests/baselines/reference/assignmentToVoidZero1.types b/tests/baselines/reference/assignmentToVoidZero1.types index 810cdff57aa0c..fd73a19bd66cb 100644 --- a/tests/baselines/reference/assignmentToVoidZero1.types +++ b/tests/baselines/reference/assignmentToVoidZero1.types @@ -2,27 +2,27 @@ // #38552 exports.y = exports.x = void 0; >exports.y = exports.x = void 0 : undefined ->exports.y : number +>exports.y : 2 >exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1") ->y : number +>y : 2 >exports.x = void 0 : undefined ->exports.x : number +>exports.x : 1 >exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1") ->x : number +>x : 1 >void 0 : undefined >0 : 0 exports.x = 1; >exports.x = 1 : 1 ->exports.x : number +>exports.x : 1 >exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1") ->x : number +>x : 1 >1 : 1 exports.y = 2; >exports.y = 2 : 2 ->exports.y : number +>exports.y : 2 >exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero1") ->y : number +>y : 2 >2 : 2 diff --git a/tests/baselines/reference/assignmentToVoidZero2.js b/tests/baselines/reference/assignmentToVoidZero2.js index c8b658474d2b8..e17f5ca275754 100644 --- a/tests/baselines/reference/assignmentToVoidZero2.js +++ b/tests/baselines/reference/assignmentToVoidZero2.js @@ -41,6 +41,6 @@ assignmentToVoidZero2_1.j + assignmentToVoidZero2_1.k; //// [assignmentToVoidZero2.d.ts] -export var j: number; +export var j: 1; //// [importer.d.ts] export {}; diff --git a/tests/baselines/reference/assignmentToVoidZero2.types b/tests/baselines/reference/assignmentToVoidZero2.types index e67f0ce830204..53455e654b2dd 100644 --- a/tests/baselines/reference/assignmentToVoidZero2.types +++ b/tests/baselines/reference/assignmentToVoidZero2.types @@ -1,9 +1,9 @@ === tests/cases/conformance/salsa/assignmentToVoidZero2.js === exports.j = 1; >exports.j = 1 : 1 ->exports.j : number +>exports.j : 1 >exports : typeof import("tests/cases/conformance/salsa/assignmentToVoidZero2") ->j : number +>j : 1 >1 : 1 exports.k = void 0; @@ -76,11 +76,11 @@ c.p + c.q === tests/cases/conformance/salsa/importer.js === import { j, k } from './assignmentToVoidZero2' ->j : number +>j : 1 >k : any j + k >j + k : any ->j : number +>j : 1 >k : any diff --git a/tests/baselines/reference/commonJsUnusedLocals.types b/tests/baselines/reference/commonJsUnusedLocals.types index 55c07a7d23046..10c61705d2356 100644 --- a/tests/baselines/reference/commonJsUnusedLocals.types +++ b/tests/baselines/reference/commonJsUnusedLocals.types @@ -5,8 +5,8 @@ const x = 0; exports.y = 1; >exports.y = 1 : 1 ->exports.y : number +>exports.y : 1 >exports : typeof import("/a") ->y : number +>y : 1 >1 : 1 diff --git a/tests/baselines/reference/commonjsAccessExports.types b/tests/baselines/reference/commonjsAccessExports.types index d33258547892f..70ba3ee15d8d1 100644 --- a/tests/baselines/reference/commonjsAccessExports.types +++ b/tests/baselines/reference/commonjsAccessExports.types @@ -1,15 +1,15 @@ === /a.js === exports.x = 0; >exports.x = 0 : 0 ->exports.x : number +>exports.x : 0 >exports : typeof import("/a") ->x : number +>x : 0 >0 : 0 exports.x; ->exports.x : number +>exports.x : 0 >exports : typeof import("/a") ->x : number +>x : 0 // Works nested { diff --git a/tests/baselines/reference/jsDeclarationsCrossfileMerge.types b/tests/baselines/reference/jsDeclarationsCrossfileMerge.types index 8de95cf8567eb..ff69429708f08 100644 --- a/tests/baselines/reference/jsDeclarationsCrossfileMerge.types +++ b/tests/baselines/reference/jsDeclarationsCrossfileMerge.types @@ -10,17 +10,17 @@ module.exports = m.default; >module.exports : typeof import("tests/cases/conformance/jsdoc/declarations/exporter").default >module : { "\"tests/cases/conformance/jsdoc/declarations/index\"": typeof import("tests/cases/conformance/jsdoc/declarations/exporter").default; } >exports : typeof import("tests/cases/conformance/jsdoc/declarations/exporter").default ->m.default : { (): void; memberName: string; } +>m.default : { (): void; memberName: "thing"; } >m : typeof import("tests/cases/conformance/jsdoc/declarations/exporter") ->default : { (): void; memberName: string; } +>default : { (): void; memberName: "thing"; } module.exports.memberName = "thing"; >module.exports.memberName = "thing" : "thing" ->module.exports.memberName : string +>module.exports.memberName : "thing" >module.exports : typeof import("tests/cases/conformance/jsdoc/declarations/exporter").default >module : { "\"tests/cases/conformance/jsdoc/declarations/index\"": typeof import("tests/cases/conformance/jsdoc/declarations/exporter").default; } >exports : typeof import("tests/cases/conformance/jsdoc/declarations/exporter").default ->memberName : string +>memberName : "thing" >"thing" : "thing" === tests/cases/conformance/jsdoc/declarations/exporter.js === diff --git a/tests/baselines/reference/jsExportAssignmentNonMutableLocation.js b/tests/baselines/reference/jsExportAssignmentNonMutableLocation.js new file mode 100644 index 0000000000000..24b1831416e65 --- /dev/null +++ b/tests/baselines/reference/jsExportAssignmentNonMutableLocation.js @@ -0,0 +1,15 @@ +//// [file.js] +const customSymbol = Symbol("custom"); + +// This is a common pattern in Node’s built-in modules: +module.exports = { + customSymbol, +}; + +exports.customSymbol2 = Symbol("custom"); + + + +//// [file.d.ts] +export const customSymbol: unique symbol; +export declare const customSymbol2: unique symbol; diff --git a/tests/baselines/reference/jsExportAssignmentNonMutableLocation.symbols b/tests/baselines/reference/jsExportAssignmentNonMutableLocation.symbols new file mode 100644 index 0000000000000..6753b39fc66b3 --- /dev/null +++ b/tests/baselines/reference/jsExportAssignmentNonMutableLocation.symbols @@ -0,0 +1,22 @@ +=== tests/cases/compiler/file.js === +const customSymbol = Symbol("custom"); +>customSymbol : Symbol(customSymbol, Decl(file.js, 0, 5)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) + +// This is a common pattern in Node’s built-in modules: +module.exports = { +>module.exports : Symbol("tests/cases/compiler/file", Decl(file.js, 0, 0)) +>module : Symbol(export=, Decl(file.js, 0, 38)) +>exports : Symbol(export=, Decl(file.js, 0, 38)) + + customSymbol, +>customSymbol : Symbol(customSymbol, Decl(file.js, 3, 18)) + +}; + +exports.customSymbol2 = Symbol("custom"); +>exports.customSymbol2 : Symbol(customSymbol2, Decl(file.js, 5, 2)) +>exports : Symbol(customSymbol2, Decl(file.js, 5, 2)) +>customSymbol2 : Symbol(customSymbol2, Decl(file.js, 5, 2)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) + diff --git a/tests/baselines/reference/jsExportAssignmentNonMutableLocation.types b/tests/baselines/reference/jsExportAssignmentNonMutableLocation.types new file mode 100644 index 0000000000000..19add7147b8cd --- /dev/null +++ b/tests/baselines/reference/jsExportAssignmentNonMutableLocation.types @@ -0,0 +1,29 @@ +=== tests/cases/compiler/file.js === +const customSymbol = Symbol("custom"); +>customSymbol : unique symbol +>Symbol("custom") : unique symbol +>Symbol : SymbolConstructor +>"custom" : "custom" + +// This is a common pattern in Node’s built-in modules: +module.exports = { +>module.exports = { customSymbol,} : { customSymbol: symbol; customSymbol2: unique symbol; } +>module.exports : { customSymbol: symbol; customSymbol2: unique symbol; } +>module : { "\"tests/cases/compiler/file\"": { customSymbol: symbol; customSymbol2: unique symbol; }; } +>exports : { customSymbol: symbol; customSymbol2: unique symbol; } +>{ customSymbol,} : { customSymbol: symbol; } + + customSymbol, +>customSymbol : symbol + +}; + +exports.customSymbol2 = Symbol("custom"); +>exports.customSymbol2 = Symbol("custom") : unique symbol +>exports.customSymbol2 : unique symbol +>exports : { customSymbol: symbol; customSymbol2: unique symbol; } +>customSymbol2 : unique symbol +>Symbol("custom") : unique symbol +>Symbol : SymbolConstructor +>"custom" : "custom" + diff --git a/tests/baselines/reference/jsExportMemberMergedWithModuleAugmentation3.types b/tests/baselines/reference/jsExportMemberMergedWithModuleAugmentation3.types index 6c66c601ffccb..ae9dc7380bd68 100644 --- a/tests/baselines/reference/jsExportMemberMergedWithModuleAugmentation3.types +++ b/tests/baselines/reference/jsExportMemberMergedWithModuleAugmentation3.types @@ -1,11 +1,11 @@ === /x.js === module.exports.x = 1; >module.exports.x = 1 : 1 ->module.exports.x : number +>module.exports.x : 1 >module.exports : typeof import("/y") >module : { "\"/x\"": typeof import("/y"); } >exports : typeof import("/y") ->x : number +>x : 1 >1 : 1 module.exports = require("./y.js"); diff --git a/tests/baselines/reference/jsFileCompilationExternalPackageError.types b/tests/baselines/reference/jsFileCompilationExternalPackageError.types index c07527fa4568f..eb87dc76d4674 100644 --- a/tests/baselines/reference/jsFileCompilationExternalPackageError.types +++ b/tests/baselines/reference/jsFileCompilationExternalPackageError.types @@ -21,9 +21,9 @@ var a = 10; === tests/cases/compiler/node_modules/c.js === exports.a = 10; >exports.a = 10 : 10 ->exports.a : number +>exports.a : 10 >exports : typeof import("tests/cases/compiler/node_modules/c") ->a : number +>a : 10 >10 : 10 c = 10; diff --git a/tests/baselines/reference/moduleExportAlias5.types b/tests/baselines/reference/moduleExportAlias5.types index e4e0b8b74b327..e6f428b615ae1 100644 --- a/tests/baselines/reference/moduleExportAlias5.types +++ b/tests/baselines/reference/moduleExportAlias5.types @@ -5,19 +5,19 @@ const webpack = function (){ >function (){} : { (): void; WebpackOptionsDefaulter: number; } } exports = module.exports = webpack; ->exports = module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: number; } ->exports : { (): void; WebpackOptionsDefaulter: number; version: number; } ->module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: number; } ->module.exports : { (): void; WebpackOptionsDefaulter: number; version: number; } ->module : { "\"tests/cases/conformance/salsa/bug24754\"": { (): void; WebpackOptionsDefaulter: number; version: number; }; } ->exports : { (): void; WebpackOptionsDefaulter: number; version: number; } +>exports = module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: 1001; } +>exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; } +>module.exports = webpack : { (): void; WebpackOptionsDefaulter: number; version: 1001; } +>module.exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; } +>module : { "\"tests/cases/conformance/salsa/bug24754\"": { (): void; WebpackOptionsDefaulter: number; version: 1001; }; } +>exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; } >webpack : { (): void; WebpackOptionsDefaulter: number; } exports.version = 1001; >exports.version = 1001 : 1001 ->exports.version : number ->exports : { (): void; WebpackOptionsDefaulter: number; version: number; } ->version : number +>exports.version : 1001 +>exports : { (): void; WebpackOptionsDefaulter: number; version: 1001; } +>version : 1001 >1001 : 1001 webpack.WebpackOptionsDefaulter = 1111; diff --git a/tests/baselines/reference/moduleExportAliasExports.types b/tests/baselines/reference/moduleExportAliasExports.types index d6c015f7f22ef..41427ccc2addf 100644 --- a/tests/baselines/reference/moduleExportAliasExports.types +++ b/tests/baselines/reference/moduleExportAliasExports.types @@ -7,16 +7,16 @@ exports.bigOak = 1 >exports.bigOak = 1 : 1 ->exports.bigOak : number +>exports.bigOak : 1 >exports : typeof import("tests/cases/conformance/salsa/Eloquent") ->bigOak : number +>bigOak : 1 >1 : 1 exports.everywhere = 2 >exports.everywhere = 2 : 2 ->exports.everywhere : number +>exports.everywhere : 2 >exports : typeof import("tests/cases/conformance/salsa/Eloquent") ->everywhere : number +>everywhere : 2 >2 : 2 module.exports = exports diff --git a/tests/baselines/reference/moduleExportAliasImported.types b/tests/baselines/reference/moduleExportAliasImported.types index 9fa087f153349..f9445477ad44a 100644 --- a/tests/baselines/reference/moduleExportAliasImported.types +++ b/tests/baselines/reference/moduleExportAliasImported.types @@ -1,9 +1,9 @@ === tests/cases/conformance/salsa/bug28014.js === exports.version = 1 >exports.version = 1 : 1 ->exports.version : number +>exports.version : 1 >exports : typeof alias ->version : number +>version : 1 >1 : 1 function alias() { } @@ -18,6 +18,6 @@ module.exports = alias === tests/cases/conformance/salsa/importer.js === import('./bug28014') ->import('./bug28014') : Promise<{ (): void; version: number; }> +>import('./bug28014') : Promise<{ (): void; version: 1; }> >'./bug28014' : "./bug28014" diff --git a/tests/baselines/reference/moduleExportAssignment.types b/tests/baselines/reference/moduleExportAssignment.types index 54fe7a2e11af4..57b4d92a0b6c8 100644 --- a/tests/baselines/reference/moduleExportAssignment.types +++ b/tests/baselines/reference/moduleExportAssignment.types @@ -58,17 +58,17 @@ npmlog.x = 1 module.exports.y = 2 >module.exports.y = 2 : 2 ->module.exports.y : number +>module.exports.y : 2 >module.exports : typeof EE >module : { "\"tests/cases/conformance/salsa/npmlog\"": typeof EE; } >exports : typeof EE ->y : number +>y : 2 >2 : 2 npmlog.y ->npmlog.y : number +>npmlog.y : 2 >npmlog : typeof EE ->y : number +>y : 2 module.exports.x >module.exports.x : number diff --git a/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.errors.txt b/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.errors.txt index bbaed77a0f90c..667446fbf6f6c 100644 --- a/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.errors.txt +++ b/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'string | number'. - Property 'toFixed' does not exist on type 'string'. -tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'string | number'. - Property 'toFixed' does not exist on type 'string'. +tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. + Property 'toFixed' does not exist on type '"string"'. +tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. + Property 'toFixed' does not exist on type '"string"'. ==== tests/cases/conformance/salsa/a.js (2 errors) ==== @@ -10,12 +10,12 @@ tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does mod1.justExport.toFixed() mod1.bothBefore.toFixed() // error, 'toFixed' not on 'string | number' ~~~~~~~ -!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'. -!!! error TS2339: Property 'toFixed' does not exist on type 'string'. +!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. +!!! error TS2339: Property 'toFixed' does not exist on type '"string"'. mod1.bothAfter.toFixed() // error, 'toFixed' not on 'string | number' ~~~~~~~ -!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'. -!!! error TS2339: Property 'toFixed' does not exist on type 'string'. +!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. +!!! error TS2339: Property 'toFixed' does not exist on type '"string"'. mod1.justProperty.length ==== tests/cases/conformance/salsa/requires.d.ts (0 errors) ==== diff --git a/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.types b/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.types index d627b9f6de150..9f16d85add984 100644 --- a/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.types +++ b/tests/baselines/reference/moduleExportWithExportPropertyAssignment3.types @@ -1,8 +1,8 @@ === tests/cases/conformance/salsa/a.js === /// var mod1 = require('./mod1') ->mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->require('./mod1') : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } +>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>require('./mod1') : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } >require : (name: string) => any >'./mod1' : "./mod1" @@ -10,31 +10,31 @@ mod1.justExport.toFixed() >mod1.justExport.toFixed() : string >mod1.justExport.toFixed : (fractionDigits?: number) => string >mod1.justExport : number ->mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } +>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } >justExport : number >toFixed : (fractionDigits?: number) => string mod1.bothBefore.toFixed() // error, 'toFixed' not on 'string | number' >mod1.bothBefore.toFixed() : any >mod1.bothBefore.toFixed : any ->mod1.bothBefore : string | number ->mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->bothBefore : string | number +>mod1.bothBefore : number | "string" +>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>bothBefore : number | "string" >toFixed : any mod1.bothAfter.toFixed() // error, 'toFixed' not on 'string | number' >mod1.bothAfter.toFixed() : any >mod1.bothAfter.toFixed : any ->mod1.bothAfter : string | number ->mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->bothAfter : string | number +>mod1.bothAfter : number | "string" +>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>bothAfter : number | "string" >toFixed : any mod1.justProperty.length >mod1.justProperty.length : number ->mod1.justProperty : string ->mod1 : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->justProperty : string +>mod1.justProperty : "string" +>mod1 : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>justProperty : "string" >length : number === tests/cases/conformance/salsa/requires.d.ts === @@ -50,18 +50,18 @@ declare function require(name: string): any; /// module.exports.bothBefore = 'string' >module.exports.bothBefore = 'string' : "string" ->module.exports.bothBefore : string | number ->module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; } ->exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->bothBefore : string | number +>module.exports.bothBefore : number | "string" +>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; } +>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>bothBefore : number | "string" >'string' : "string" module.exports = { ->module.exports = { justExport: 1, bothBefore: 2, bothAfter: 3,} : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; } ->exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } +>module.exports = { justExport: 1, bothBefore: 2, bothAfter: 3,} : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; } +>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } >{ justExport: 1, bothBefore: 2, bothAfter: 3,} : { justExport: number; bothBefore: number; bothAfter: number; } justExport: 1, @@ -78,19 +78,19 @@ module.exports = { } module.exports.bothAfter = 'string' >module.exports.bothAfter = 'string' : "string" ->module.exports.bothAfter : string | number ->module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; } ->exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->bothAfter : string | number +>module.exports.bothAfter : number | "string" +>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; } +>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>bothAfter : number | "string" >'string' : "string" module.exports.justProperty = 'string' >module.exports.justProperty = 'string' : "string" ->module.exports.justProperty : string ->module.exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; }; } ->exports : { justExport: number; bothBefore: string | number; bothAfter: string | number; justProperty: string; } ->justProperty : string +>module.exports.justProperty : "string" +>module.exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>module : { "\"tests/cases/conformance/salsa/mod1\"": { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; }; } +>exports : { justExport: number; bothBefore: number | "string"; bothAfter: number | "string"; justProperty: "string"; } +>justProperty : "string" >'string' : "string" diff --git a/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.errors.txt b/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.errors.txt index f44a5c2b47e86..8ff40a89e57aa 100644 --- a/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.errors.txt +++ b/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'string | number'. - Property 'toFixed' does not exist on type 'string'. -tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'string | number'. - Property 'toFixed' does not exist on type 'string'. +tests/cases/conformance/salsa/a.js(4,17): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. + Property 'toFixed' does not exist on type '"string"'. +tests/cases/conformance/salsa/a.js(5,16): error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. + Property 'toFixed' does not exist on type '"string"'. tests/cases/conformance/salsa/mod1.js(2,1): error TS2323: Cannot redeclare exported variable 'bothBefore'. tests/cases/conformance/salsa/mod1.js(4,1): error TS2323: Cannot redeclare exported variable 'bothBefore'. tests/cases/conformance/salsa/mod1.js(5,1): error TS2323: Cannot redeclare exported variable 'bothAfter'. @@ -14,12 +14,12 @@ tests/cases/conformance/salsa/mod1.js(10,1): error TS2323: Cannot redeclare expo mod1.justExport.toFixed() mod1.bothBefore.toFixed() // error ~~~~~~~ -!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'. -!!! error TS2339: Property 'toFixed' does not exist on type 'string'. +!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. +!!! error TS2339: Property 'toFixed' does not exist on type '"string"'. mod1.bothAfter.toFixed() ~~~~~~~ -!!! error TS2339: Property 'toFixed' does not exist on type 'string | number'. -!!! error TS2339: Property 'toFixed' does not exist on type 'string'. +!!! error TS2339: Property 'toFixed' does not exist on type 'number | "string"'. +!!! error TS2339: Property 'toFixed' does not exist on type '"string"'. mod1.justProperty.length ==== tests/cases/conformance/salsa/requires.d.ts (0 errors) ==== diff --git a/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.types b/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.types index 0ddaff1d58a90..f9bc50942d114 100644 --- a/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.types +++ b/tests/baselines/reference/moduleExportWithExportPropertyAssignment4.types @@ -17,24 +17,24 @@ mod1.justExport.toFixed() mod1.bothBefore.toFixed() // error >mod1.bothBefore.toFixed() : any >mod1.bothBefore.toFixed : any ->mod1.bothBefore : string | number +>mod1.bothBefore : number | "string" >mod1 : typeof import("tests/cases/conformance/salsa/mod1") ->bothBefore : string | number +>bothBefore : number | "string" >toFixed : any mod1.bothAfter.toFixed() >mod1.bothAfter.toFixed() : any >mod1.bothAfter.toFixed : any ->mod1.bothAfter : string | number +>mod1.bothAfter : number | "string" >mod1 : typeof import("tests/cases/conformance/salsa/mod1") ->bothAfter : string | number +>bothAfter : number | "string" >toFixed : any mod1.justProperty.length >mod1.justProperty.length : number ->mod1.justProperty : string +>mod1.justProperty : "string" >mod1 : typeof import("tests/cases/conformance/salsa/mod1") ->justProperty : string +>justProperty : "string" >length : number === tests/cases/conformance/salsa/requires.d.ts === @@ -50,11 +50,11 @@ declare function require(name: string): any; /// module.exports.bothBefore = 'string' >module.exports.bothBefore = 'string' : "string" ->module.exports.bothBefore : string | number +>module.exports.bothBefore : number | "string" >module.exports : typeof A >module : { "\"tests/cases/conformance/salsa/mod1\"": typeof A; } >exports : typeof A ->bothBefore : string | number +>bothBefore : number | "string" >'string' : "string" A.justExport = 4 @@ -66,16 +66,16 @@ A.justExport = 4 A.bothBefore = 2 >A.bothBefore = 2 : 2 ->A.bothBefore : string | number +>A.bothBefore : number | "string" >A : typeof A ->bothBefore : string | number +>bothBefore : number | "string" >2 : 2 A.bothAfter = 3 >A.bothAfter = 3 : 3 ->A.bothAfter : string | number +>A.bothAfter : number | "string" >A : typeof A ->bothAfter : string | number +>bothAfter : number | "string" >3 : 3 module.exports = A @@ -97,19 +97,19 @@ function A() { } module.exports.bothAfter = 'string' >module.exports.bothAfter = 'string' : "string" ->module.exports.bothAfter : string | number +>module.exports.bothAfter : number | "string" >module.exports : typeof A >module : { "\"tests/cases/conformance/salsa/mod1\"": typeof A; } >exports : typeof A ->bothAfter : string | number +>bothAfter : number | "string" >'string' : "string" module.exports.justProperty = 'string' >module.exports.justProperty = 'string' : "string" ->module.exports.justProperty : string +>module.exports.justProperty : "string" >module.exports : typeof A >module : { "\"tests/cases/conformance/salsa/mod1\"": typeof A; } >exports : typeof A ->justProperty : string +>justProperty : "string" >'string' : "string" diff --git a/tests/baselines/reference/moduleResolution_explicitNodeModulesImport.types b/tests/baselines/reference/moduleResolution_explicitNodeModulesImport.types index fabd2b69a4c82..f048ba25d7b79 100644 --- a/tests/baselines/reference/moduleResolution_explicitNodeModulesImport.types +++ b/tests/baselines/reference/moduleResolution_explicitNodeModulesImport.types @@ -1,12 +1,12 @@ === /src/index.ts === import { x } from "../node_modules/foo"; ->x : number +>x : 0 === /node_modules/foo/index.js === exports.x = 0; >exports.x = 0 : 0 ->exports.x : number +>exports.x : 0 >exports : typeof import("/node_modules/foo/index") ->x : number +>x : 0 >0 : 0 diff --git a/tests/baselines/reference/typedefCrossModule2.types b/tests/baselines/reference/typedefCrossModule2.types index 9a1b0922f9e64..31cdb777c98e1 100644 --- a/tests/baselines/reference/typedefCrossModule2.types +++ b/tests/baselines/reference/typedefCrossModule2.types @@ -1,7 +1,7 @@ === tests/cases/conformance/jsdoc/use.js === var mod = require('./mod1.js'); ->mod : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } ->require('./mod1.js') : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } +>mod : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } +>require('./mod1.js') : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } >require : any >'./mod1.js' : "./mod1.js" @@ -17,7 +17,7 @@ var bbb = new mod.Baz(); >bbb : any >new mod.Baz() : any >mod.Baz : any ->mod : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } +>mod : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } >Baz : any === tests/cases/conformance/jsdoc/mod1.js === @@ -31,16 +31,16 @@ class Foo { } // should error exports.Bar = class { } >exports.Bar = class { } : typeof Bar >exports.Bar : typeof Bar ->exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } +>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } >Bar : typeof Bar >class { } : typeof Bar /** @typedef {number} Baz */ module.exports = { ->module.exports = { Baz: class { }} : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } ->module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } ->module : { "\"tests/cases/conformance/jsdoc/mod1\"": { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }; } ->exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } +>module.exports = { Baz: class { }} : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } +>module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } +>module : { "\"tests/cases/conformance/jsdoc/mod1\"": { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }; } +>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } >{ Baz: class { }} : { Baz: typeof Baz; } Baz: class { } @@ -58,17 +58,17 @@ var Qux = 2; /** @typedef {number} Quid */ exports.Quid = 2; >exports.Quid = 2 : 2 ->exports.Quid : number ->exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } ->Quid : number +>exports.Quid : 2 +>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } +>Quid : 2 >2 : 2 /** @typedef {number} Quack */ module.exports = { ->module.exports = { Quack: 2} : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } ->module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } ->module : { "\"tests/cases/conformance/jsdoc/mod1\"": { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; }; } ->exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: number; } | { Quack: number; Bar: typeof Bar; Quid: number; } +>module.exports = { Quack: 2} : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } +>module.exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } +>module : { "\"tests/cases/conformance/jsdoc/mod1\"": { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; }; } +>exports : { Baz: typeof Baz; Bar: typeof Bar; Quid: 2; } | { Quack: number; Bar: typeof Bar; Quid: 2; } >{ Quack: 2} : { Quack: number; } Quack: 2 diff --git a/tests/cases/compiler/jsExportAssignmentNonMutableLocation.ts b/tests/cases/compiler/jsExportAssignmentNonMutableLocation.ts new file mode 100644 index 0000000000000..a0eef7f86ecad --- /dev/null +++ b/tests/cases/compiler/jsExportAssignmentNonMutableLocation.ts @@ -0,0 +1,15 @@ +// @declaration: true +// @emitDeclarationOnly: true +// @allowJs: true +// @checkJs: true +// @module: commonjs +// @target: es6 +// @filename: file.js +const customSymbol = Symbol("custom"); + +// This is a common pattern in Node’s built-in modules: +module.exports = { + customSymbol, +}; + +exports.customSymbol2 = Symbol("custom"); \ No newline at end of file From 380990f87e2163541fc630a250c3d00e2fb63633 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 31 Jul 2020 11:02:23 -0700 Subject: [PATCH 2/3] Style feedback from PR --- src/compiler/checker.ts | 6 ++++-- src/compiler/utilities.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 6218e46c04246..5e1e064960821 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8070,7 +8070,9 @@ namespace ts { return anyType; } const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); - const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) : (isDirectExport ? getRegularTypeOfLiteralType : getWidenedLiteralType)(checkExpressionCached(expression.right)); + const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) + : isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right)) + : getWidenedLiteralType(checkExpressionCached(expression.right)); if (type.flags & TypeFlags.Object && kind === AssignmentDeclarationKind.ModuleExports && symbol.escapedName === InternalSymbolName.ExportEquals) { @@ -29889,7 +29891,7 @@ namespace ts { function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type { const type = checkExpression(node, checkMode, forceTuple); - return isConstContext(node) || isCommonJsExportedExpresion(node) ? getRegularTypeOfLiteralType(type) : + return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) : isTypeAssertion(node) ? type : getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node) : contextualType, node)); } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 383b5484713ec..bc6ca82223023 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1345,7 +1345,7 @@ namespace ts { && node.parent.parent.kind === SyntaxKind.VariableStatement; } - export function isCommonJsExportedExpresion(node: Node) { + export function isCommonJsExportedExpression(node: Node) { if (!isInJSFile(node)) return false; return (isObjectLiteralExpression(node.parent) && isBinaryExpression(node.parent.parent) && getAssignmentDeclarationKind(node.parent.parent) === AssignmentDeclarationKind.ModuleExports) || isCommonJsExportPropertyAssignment(node.parent); From 90311dc2992f5e1cb85d26a6c52dde3d3494be22 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 31 Jul 2020 11:59:55 -0700 Subject: [PATCH 3/3] Trailing whitespaaaaace --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5e1e064960821..264372874ead2 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -8070,8 +8070,8 @@ namespace ts { return anyType; } const isDirectExport = kind === AssignmentDeclarationKind.ExportsProperty && (isPropertyAccessExpression(expression.left) || isElementAccessExpression(expression.left)) && (isModuleExportsAccessExpression(expression.left.expression) || (isIdentifier(expression.left.expression) && isExportsIdentifier(expression.left.expression))); - const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) - : isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right)) + const type = resolvedSymbol ? getTypeOfSymbol(resolvedSymbol) + : isDirectExport ? getRegularTypeOfLiteralType(checkExpressionCached(expression.right)) : getWidenedLiteralType(checkExpressionCached(expression.right)); if (type.flags & TypeFlags.Object && kind === AssignmentDeclarationKind.ModuleExports &&