Skip to content

Commit

Permalink
isolatedModules error on global shadowed by imported type (microsoft#…
Browse files Browse the repository at this point in the history
  • Loading branch information
frigus02 authored and c0sta committed Dec 20, 2023
1 parent 18f5d3f commit ed79345
Show file tree
Hide file tree
Showing 6 changed files with 270 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,7 @@ import {
isTypeNode,
isTypeNodeKind,
isTypeOfExpression,
isTypeOnlyImportDeclaration,
isTypeOnlyImportOrExportDeclaration,
isTypeOperatorNode,
isTypeParameterDeclaration,
Expand Down Expand Up @@ -3603,6 +3604,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
}
}

// Look at 'compilerOptions.isolatedModules' and not 'getIsolatedModules(...)' (which considers 'verbatimModuleSyntax')
// here because 'verbatimModuleSyntax' will already have an error for importing a type without 'import type'.
if (compilerOptions.isolatedModules && result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value) {
const isGlobal = lookup(globals, name, meaning) === result;
const nonValueSymbol = isGlobal && isSourceFile(lastLocation!) && lastLocation.locals && lookup(lastLocation.locals, name, ~SymbolFlags.Value);
if (nonValueSymbol) {
const importDecl = nonValueSymbol.declarations?.find(d => d.kind === SyntaxKind.ImportSpecifier || d.kind === SyntaxKind.ImportClause || d.kind === SyntaxKind.NamespaceImport || d.kind === SyntaxKind.ImportEqualsDeclaration);
if (importDecl && !isTypeOnlyImportDeclaration(importDecl)) {
error(importDecl, Diagnostics.Import_0_conflicts_with_global_value_used_in_this_file_so_must_be_declared_with_a_type_only_import_when_isolatedModules_is_enabled, unescapeLeadingUnderscores(name));
}
}
}
});
}
return result;
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3731,6 +3731,10 @@
"category": "Error",
"code": 2865
},
"Import '{0}' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.": {
"category": "Error",
"code": 2866
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
bad.ts(1,10): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
bad.ts(1,10): error TS1484: 'Date' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
bad.ts(1,16): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
bad.ts(1,16): error TS1484: 'Event' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
good.ts(2,10): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.


==== ./types.ts (0 errors) ====
export interface Date {
day: number;
month: number;
year: number;
}

export namespace Event {
export type T = any;
}

==== ./node.d.ts (0 errors) ====
declare module 'node:console' {
global {
interface Console {
Console: console.ConsoleConstructor;
}
namespace console {
interface ConsoleConstructor {
prototype: Console;
new (): Console;
}
}
var console: Console;
}
export = globalThis.console;
}

==== ./bad.ts (4 errors) ====
import { Date, Event } from './types';
~~~~
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
~~~~
!!! error TS1484: 'Date' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
~~~~~
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
~~~~~
!!! error TS1484: 'Event' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}

==== ./good.ts (1 errors) ====
import type { Date, Event } from './types';
import { Console } from 'node:console';
~~~~~~~
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}
const baz: Console = new Console();

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
bad.ts(1,10): error TS2866: Import 'Date' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.
bad.ts(1,16): error TS2866: Import 'Event' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.


==== ./types.ts (0 errors) ====
export interface Date {
day: number;
month: number;
year: number;
}

export namespace Event {
export type T = any;
}

==== ./node.d.ts (0 errors) ====
declare module 'node:console' {
global {
interface Console {
Console: console.ConsoleConstructor;
}
namespace console {
interface ConsoleConstructor {
prototype: Console;
new (): Console;
}
}
var console: Console;
}
export = globalThis.console;
}

==== ./bad.ts (2 errors) ====
import { Date, Event } from './types';
~~~~
!!! error TS2866: Import 'Date' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.
~~~~~
!!! error TS2866: Import 'Event' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}

==== ./good.ts (0 errors) ====
import type { Date, Event } from './types';
import { Console } from 'node:console';
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}
const baz: Console = new Console();

Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
bad.ts(1,10): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
bad.ts(1,10): error TS1484: 'Date' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
bad.ts(1,10): error TS2866: Import 'Date' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.
bad.ts(1,16): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
bad.ts(1,16): error TS1484: 'Event' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
bad.ts(1,16): error TS2866: Import 'Event' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.
good.ts(2,10): error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.


==== ./types.ts (0 errors) ====
export interface Date {
day: number;
month: number;
year: number;
}

export namespace Event {
export type T = any;
}

==== ./node.d.ts (0 errors) ====
declare module 'node:console' {
global {
interface Console {
Console: console.ConsoleConstructor;
}
namespace console {
interface ConsoleConstructor {
prototype: Console;
new (): Console;
}
}
var console: Console;
}
export = globalThis.console;
}

==== ./bad.ts (6 errors) ====
import { Date, Event } from './types';
~~~~
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
~~~~
!!! error TS1484: 'Date' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
~~~~
!!! error TS2866: Import 'Date' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.
~~~~~
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
~~~~~
!!! error TS1484: 'Event' is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled.
~~~~~
!!! error TS2866: Import 'Event' conflicts with global value used in this file, so must be declared with a type-only import when 'isolatedModules' is enabled.
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}

==== ./good.ts (1 errors) ====
import type { Date, Event } from './types';
import { Console } from 'node:console';
~~~~~~~
!!! error TS1286: ESM syntax is not allowed in a CommonJS module when 'verbatimModuleSyntax' is enabled.
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}
const baz: Console = new Console();

54 changes: 54 additions & 0 deletions tests/cases/compiler/isolatedModulesShadowGlobalTypeNotValue.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// @isolatedModules: false, true
// @verbatimModuleSyntax: false, true
// @noEmit: true
// @noTypesAndSymbols: true

// @filename: ./types.ts
export interface Date {
day: number;
month: number;
year: number;
}

export namespace Event {
export type T = any;
}

// @filename: ./node.d.ts
declare module 'node:console' {
global {
interface Console {
Console: console.ConsoleConstructor;
}
namespace console {
interface ConsoleConstructor {
prototype: Console;
new (): Console;
}
}
var console: Console;
}
export = globalThis.console;
}

// @filename: ./bad.ts
import { Date, Event } from './types';
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}

// @filename: ./good.ts
import type { Date, Event } from './types';
import { Console } from 'node:console';
function foo(a: Date) {
const b = new Date(a.year, a.month, a.day);
return b.getTime();
}
function bar() {
return new Event('bar') as Event.T;
}
const baz: Console = new Console();

0 comments on commit ed79345

Please sign in to comment.