From 46e8306050b957aad4e72d2c48c2f75dd12afdc3 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 5 May 2022 09:33:32 -0700 Subject: [PATCH] Skip ambient modules in globalThis (#48938) * Skip ambient modules in globalThis Previously, globalThis mistakenly included ambient modules, even though these are not values: ```ts declare module "ambientModule" { export type typ = 1 export var val: typ } type Oops = (typeof globalThis)[\"ambientModule\"] ``` This PR adds ambient modules to the kinds of things that are skipped when constructing `globalThis`' properties, along with block-scoped variables. * Skip only modules with every declaration ambient The modules are required to have at least one declaration so that our treatment of `globalThis` stays the same, and `globalThis.globalThis.globalThis` remains legal. --- src/compiler/checker.ts | 2 +- .../globalThisAmbientModules.errors.txt | 21 ++++++++++ .../reference/globalThisAmbientModules.js | 20 ++++++++++ .../globalThisAmbientModules.symbols | 38 +++++++++++++++++++ .../reference/globalThisAmbientModules.types | 37 ++++++++++++++++++ .../es2019/globalThisAmbientModules.ts | 11 ++++++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/globalThisAmbientModules.errors.txt create mode 100644 tests/baselines/reference/globalThisAmbientModules.js create mode 100644 tests/baselines/reference/globalThisAmbientModules.symbols create mode 100644 tests/baselines/reference/globalThisAmbientModules.types create mode 100644 tests/cases/conformance/es2019/globalThisAmbientModules.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8dc1e1df76f..504cdf669c7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11504,7 +11504,7 @@ namespace ts { if (symbol === globalThisSymbol) { const varsOnly = new Map() as SymbolTable; members.forEach(p => { - if (!(p.flags & SymbolFlags.BlockScoped)) { + if (!(p.flags & SymbolFlags.BlockScoped) && !(p.flags & SymbolFlags.ValueModule && p.declarations?.length && every(p.declarations, isAmbientModule))) { varsOnly.set(p.escapedName, p); } }); diff --git a/tests/baselines/reference/globalThisAmbientModules.errors.txt b/tests/baselines/reference/globalThisAmbientModules.errors.txt new file mode 100644 index 00000000000..b29d977475f --- /dev/null +++ b/tests/baselines/reference/globalThisAmbientModules.errors.txt @@ -0,0 +1,21 @@ +tests/cases/conformance/es2019/globalThisAmbientModules.ts(8,39): error TS2339: Property '"ambientModule"' does not exist on type 'typeof globalThis'. +tests/cases/conformance/es2019/globalThisAmbientModules.ts(11,33): error TS2339: Property '"ambientModule"' does not exist on type 'typeof globalThis'. + + +==== tests/cases/conformance/es2019/globalThisAmbientModules.ts (2 errors) ==== + declare module "ambientModule" { + export type typ = 1 + export var val: typ + } + namespace valueModule { export var val = 1 } + namespace namespaceModule { export type typ = 1 } + // should error + type GlobalBad1 = (typeof globalThis)["\"ambientModule\""] + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2339: Property '"ambientModule"' does not exist on type 'typeof globalThis'. + type GlobalOk1 = (typeof globalThis)["valueModule"] + type GlobalOk2 = globalThis.namespaceModule.typ + const bad1: (typeof globalThis)["\"ambientModule\""] = 'ambientModule' + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2339: Property '"ambientModule"' does not exist on type 'typeof globalThis'. + \ No newline at end of file diff --git a/tests/baselines/reference/globalThisAmbientModules.js b/tests/baselines/reference/globalThisAmbientModules.js new file mode 100644 index 00000000000..ec032568e9b --- /dev/null +++ b/tests/baselines/reference/globalThisAmbientModules.js @@ -0,0 +1,20 @@ +//// [globalThisAmbientModules.ts] +declare module "ambientModule" { + export type typ = 1 + export var val: typ +} +namespace valueModule { export var val = 1 } +namespace namespaceModule { export type typ = 1 } +// should error +type GlobalBad1 = (typeof globalThis)["\"ambientModule\""] +type GlobalOk1 = (typeof globalThis)["valueModule"] +type GlobalOk2 = globalThis.namespaceModule.typ +const bad1: (typeof globalThis)["\"ambientModule\""] = 'ambientModule' + + +//// [globalThisAmbientModules.js] +var valueModule; +(function (valueModule) { + valueModule.val = 1; +})(valueModule || (valueModule = {})); +var bad1 = 'ambientModule'; diff --git a/tests/baselines/reference/globalThisAmbientModules.symbols b/tests/baselines/reference/globalThisAmbientModules.symbols new file mode 100644 index 00000000000..f27f2461baa --- /dev/null +++ b/tests/baselines/reference/globalThisAmbientModules.symbols @@ -0,0 +1,38 @@ +=== tests/cases/conformance/es2019/globalThisAmbientModules.ts === +declare module "ambientModule" { +>"ambientModule" : Symbol("ambientModule", Decl(globalThisAmbientModules.ts, 0, 0)) + + export type typ = 1 +>typ : Symbol(typ, Decl(globalThisAmbientModules.ts, 0, 32)) + + export var val: typ +>val : Symbol(val, Decl(globalThisAmbientModules.ts, 2, 14)) +>typ : Symbol(typ, Decl(globalThisAmbientModules.ts, 0, 32)) +} +namespace valueModule { export var val = 1 } +>valueModule : Symbol(valueModule, Decl(globalThisAmbientModules.ts, 3, 1)) +>val : Symbol(val, Decl(globalThisAmbientModules.ts, 4, 34)) + +namespace namespaceModule { export type typ = 1 } +>namespaceModule : Symbol(namespaceModule, Decl(globalThisAmbientModules.ts, 4, 44)) +>typ : Symbol(typ, Decl(globalThisAmbientModules.ts, 5, 27)) + +// should error +type GlobalBad1 = (typeof globalThis)["\"ambientModule\""] +>GlobalBad1 : Symbol(GlobalBad1, Decl(globalThisAmbientModules.ts, 5, 49)) +>globalThis : Symbol(globalThis) + +type GlobalOk1 = (typeof globalThis)["valueModule"] +>GlobalOk1 : Symbol(GlobalOk1, Decl(globalThisAmbientModules.ts, 7, 58)) +>globalThis : Symbol(globalThis) + +type GlobalOk2 = globalThis.namespaceModule.typ +>GlobalOk2 : Symbol(GlobalOk2, Decl(globalThisAmbientModules.ts, 8, 51)) +>globalThis : Symbol(globalThis) +>namespaceModule : Symbol(namespaceModule, Decl(globalThisAmbientModules.ts, 4, 44)) +>typ : Symbol(namespaceModule.typ, Decl(globalThisAmbientModules.ts, 5, 27)) + +const bad1: (typeof globalThis)["\"ambientModule\""] = 'ambientModule' +>bad1 : Symbol(bad1, Decl(globalThisAmbientModules.ts, 10, 5)) +>globalThis : Symbol(globalThis) + diff --git a/tests/baselines/reference/globalThisAmbientModules.types b/tests/baselines/reference/globalThisAmbientModules.types new file mode 100644 index 00000000000..9357ee67ead --- /dev/null +++ b/tests/baselines/reference/globalThisAmbientModules.types @@ -0,0 +1,37 @@ +=== tests/cases/conformance/es2019/globalThisAmbientModules.ts === +declare module "ambientModule" { +>"ambientModule" : typeof import("ambientModule") + + export type typ = 1 +>typ : 1 + + export var val: typ +>val : 1 +} +namespace valueModule { export var val = 1 } +>valueModule : typeof valueModule +>val : number +>1 : 1 + +namespace namespaceModule { export type typ = 1 } +>typ : 1 + +// should error +type GlobalBad1 = (typeof globalThis)["\"ambientModule\""] +>GlobalBad1 : any +>globalThis : typeof globalThis + +type GlobalOk1 = (typeof globalThis)["valueModule"] +>GlobalOk1 : typeof valueModule +>globalThis : typeof globalThis + +type GlobalOk2 = globalThis.namespaceModule.typ +>GlobalOk2 : 1 +>globalThis : any +>namespaceModule : any + +const bad1: (typeof globalThis)["\"ambientModule\""] = 'ambientModule' +>bad1 : any +>globalThis : typeof globalThis +>'ambientModule' : "ambientModule" + diff --git a/tests/cases/conformance/es2019/globalThisAmbientModules.ts b/tests/cases/conformance/es2019/globalThisAmbientModules.ts new file mode 100644 index 00000000000..5f170a0de27 --- /dev/null +++ b/tests/cases/conformance/es2019/globalThisAmbientModules.ts @@ -0,0 +1,11 @@ +declare module "ambientModule" { + export type typ = 1 + export var val: typ +} +namespace valueModule { export var val = 1 } +namespace namespaceModule { export type typ = 1 } +// should error +type GlobalBad1 = (typeof globalThis)["\"ambientModule\""] +type GlobalOk1 = (typeof globalThis)["valueModule"] +type GlobalOk2 = globalThis.namespaceModule.typ +const bad1: (typeof globalThis)["\"ambientModule\""] = 'ambientModule'