diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 82fc1f490a4f4..0d7adfafede23 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -36430,21 +36430,32 @@ namespace ts {
* marked as referenced to prevent import elision.
*/
function markTypeNodeAsReferenced(node: TypeNode) {
- markEntityNameOrEntityExpressionAsReference(node && getEntityNameFromTypeNode(node));
+ markEntityNameOrEntityExpressionAsReference(node && getEntityNameFromTypeNode(node), /*forDecoratorMetadata*/ false);
}
- function markEntityNameOrEntityExpressionAsReference(typeName: EntityNameOrEntityNameExpression | undefined) {
+ function markEntityNameOrEntityExpressionAsReference(typeName: EntityNameOrEntityNameExpression | undefined, forDecoratorMetadata: boolean) {
if (!typeName) return;
const rootName = getFirstIdentifier(typeName);
const meaning = (typeName.kind === SyntaxKind.Identifier ? SymbolFlags.Type : SymbolFlags.Namespace) | SymbolFlags.Alias;
const rootSymbol = resolveName(rootName, rootName.escapedText, meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isReference*/ true);
- if (rootSymbol
- && rootSymbol.flags & SymbolFlags.Alias
- && symbolIsValue(rootSymbol)
- && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol))
- && !getTypeOnlyAliasDeclaration(rootSymbol)) {
- markAliasSymbolAsReferenced(rootSymbol);
+ if (rootSymbol && rootSymbol.flags & SymbolFlags.Alias) {
+ if (symbolIsValue(rootSymbol)
+ && !isConstEnumOrConstEnumOnlyModule(resolveAlias(rootSymbol))
+ && !getTypeOnlyAliasDeclaration(rootSymbol)) {
+ markAliasSymbolAsReferenced(rootSymbol);
+ }
+ else if (forDecoratorMetadata
+ && compilerOptions.isolatedModules
+ && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015
+ && !symbolIsValue(rootSymbol)
+ && !some(rootSymbol.declarations, isTypeOnlyImportOrExportDeclaration)) {
+ const diag = error(typeName, Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled);
+ const aliasDeclaration = find(rootSymbol.declarations || emptyArray, isAliasSymbolDeclaration);
+ if (aliasDeclaration) {
+ addRelatedInfo(diag, createDiagnosticForNode(aliasDeclaration, Diagnostics._0_was_imported_here, idText(rootName)));
+ }
+ }
}
}
@@ -36458,7 +36469,7 @@ namespace ts {
function markDecoratorMedataDataTypeNodeAsReferenced(node: TypeNode | undefined): void {
const entityName = getEntityNameForDecoratorMetadata(node);
if (entityName && isEntityName(entityName)) {
- markEntityNameOrEntityExpressionAsReference(entityName);
+ markEntityNameOrEntityExpressionAsReference(entityName, /*forDecoratorMetadata*/ true);
}
}
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index cf86150ee3b24..affe89f5b2cb1 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -879,6 +879,10 @@
"category": "Error",
"code": 1271
},
+ "A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.": {
+ "category": "Error",
+ "code": 1272
+ },
"'with' statements are not allowed in an async function block.": {
"category": "Error",
@@ -7174,6 +7178,7 @@
"code": 95173
},
+
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
"category": "Error",
"code": 18004
diff --git a/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts b/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts
new file mode 100644
index 0000000000000..30fefde64efed
--- /dev/null
+++ b/src/services/codefixes/fixUnreferenceableDecoratorMetadata.ts
@@ -0,0 +1,70 @@
+/* @internal */
+namespace ts.codefix {
+ const fixId = "fixUnreferenceableDecoratorMetadata";
+ const errorCodes = [Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled.code];
+ registerCodeFix({
+ errorCodes,
+ getCodeActions: context => {
+ const importDeclaration = getImportDeclaration(context.sourceFile, context.program, context.span.start);
+ if (!importDeclaration) return;
+
+ const namespaceChanges = textChanges.ChangeTracker.with(context, t => importDeclaration.kind === SyntaxKind.ImportSpecifier && doNamespaceImportChange(t, context.sourceFile, importDeclaration, context.program));
+ const typeOnlyChanges = textChanges.ChangeTracker.with(context, t => doTypeOnlyImportChange(t, context.sourceFile, importDeclaration, context.program));
+ let actions: CodeFixAction[] | undefined;
+ if (namespaceChanges.length) {
+ actions = append(actions, createCodeFixActionWithoutFixAll(fixId, namespaceChanges, Diagnostics.Convert_named_imports_to_namespace_import));
+ }
+ if (typeOnlyChanges.length) {
+ actions = append(actions, createCodeFixActionWithoutFixAll(fixId, typeOnlyChanges, Diagnostics.Convert_to_type_only_import));
+ }
+ return actions;
+ },
+ fixIds: [fixId],
+ });
+
+ function getImportDeclaration(sourceFile: SourceFile, program: Program, start: number): ImportClause | ImportSpecifier | ImportEqualsDeclaration | undefined {
+ const identifier = tryCast(getTokenAtPosition(sourceFile, start), isIdentifier);
+ if (!identifier || identifier.parent.kind !== SyntaxKind.TypeReference) return;
+
+ const checker = program.getTypeChecker();
+ const symbol = checker.getSymbolAtLocation(identifier);
+ return find(symbol?.declarations || emptyArray, or(isImportClause, isImportSpecifier, isImportEqualsDeclaration) as (n: Node) => n is ImportClause | ImportSpecifier | ImportEqualsDeclaration);
+ }
+
+ // Converts the import declaration of the offending import to a type-only import,
+ // only if it can be done without affecting other imported names. If the conversion
+ // cannot be done cleanly, we could offer to *extract* the offending import to a
+ // new type-only import declaration, but honestly I doubt anyone will ever use this
+ // codefix at all, so it's probably not worth the lines of code.
+ function doTypeOnlyImportChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDeclaration: ImportClause | ImportSpecifier | ImportEqualsDeclaration, program: Program) {
+ if (importDeclaration.kind === SyntaxKind.ImportEqualsDeclaration) {
+ changes.insertModifierBefore(sourceFile, SyntaxKind.TypeKeyword, importDeclaration.name);
+ return;
+ }
+
+ const importClause = importDeclaration.kind === SyntaxKind.ImportClause ? importDeclaration : importDeclaration.parent.parent;
+ if (importClause.name && importClause.namedBindings) {
+ // Cannot convert an import with a default import and named bindings to type-only
+ // (it's a grammar error).
+ return;
+ }
+
+ const checker = program.getTypeChecker();
+ const importsValue = !!forEachImportClauseDeclaration(importClause, decl => {
+ if (skipAlias(decl.symbol, checker).flags & SymbolFlags.Value) return true;
+ });
+
+ if (importsValue) {
+ // Assume that if someone wrote a non-type-only import that includes some values,
+ // they intend to use those values in value positions, even if they haven't yet.
+ // Don't convert it to type-only.
+ return;
+ }
+
+ changes.insertModifierBefore(sourceFile, SyntaxKind.TypeKeyword, importClause);
+ }
+
+ function doNamespaceImportChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, importDeclaration: ImportSpecifier, program: Program) {
+ refactor.doChangeNamedToNamespaceOrDefault(sourceFile, program, changes, importDeclaration.parent);
+ }
+}
diff --git a/src/services/refactors/convertImport.ts b/src/services/refactors/convertImport.ts
index 3589e3006c1bf..01333162abb14 100644
--- a/src/services/refactors/convertImport.ts
+++ b/src/services/refactors/convertImport.ts
@@ -79,22 +79,25 @@ namespace ts.refactor {
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
return { convertTo: ImportKind.Named, import: importClause.namedBindings };
}
- const compilerOptions = context.program.getCompilerOptions();
- const shouldUseDefault = getAllowSyntheticDefaultImports(compilerOptions)
- && isExportEqualsModule(importClause.parent.moduleSpecifier, context.program.getTypeChecker());
+ const shouldUseDefault = getShouldUseDefault(context.program, importClause);
return shouldUseDefault
? { convertTo: ImportKind.Default, import: importClause.namedBindings }
: { convertTo: ImportKind.Namespace, import: importClause.namedBindings };
}
+ function getShouldUseDefault(program: Program, importClause: ImportClause) {
+ return getAllowSyntheticDefaultImports(program.getCompilerOptions())
+ && isExportEqualsModule(importClause.parent.moduleSpecifier, program.getTypeChecker());
+ }
+
function doChange(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, info: ImportConversionInfo): void {
const checker = program.getTypeChecker();
if (info.convertTo === ImportKind.Named) {
doChangeNamespaceToNamed(sourceFile, checker, changes, info.import, getAllowSyntheticDefaultImports(program.getCompilerOptions()));
}
else {
- doChangeNamedToNamespaceOrDefault(sourceFile, checker, changes, info.import, info.convertTo === ImportKind.Default);
+ doChangeNamedToNamespaceOrDefault(sourceFile, program, changes, info.import, info.convertTo === ImportKind.Default);
}
}
@@ -153,7 +156,8 @@ namespace ts.refactor {
return isPropertyAccessExpression(propertyAccessOrQualifiedName) ? propertyAccessOrQualifiedName.expression : propertyAccessOrQualifiedName.left;
}
- function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, toConvert: NamedImports, shouldUseDefault: boolean) {
+ export function doChangeNamedToNamespaceOrDefault(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, toConvert: NamedImports, shouldUseDefault = getShouldUseDefault(program, toConvert.parent)): void {
+ const checker = program.getTypeChecker();
const importDecl = toConvert.parent.parent;
const { moduleSpecifier } = importDecl;
diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json
index 3cd2188314613..cef6b9139698a 100644
--- a/src/services/tsconfig.json
+++ b/src/services/tsconfig.json
@@ -88,6 +88,7 @@
"codefixes/fixForgottenThisPropertyAccess.ts",
"codefixes/fixInvalidJsxCharacters.ts",
"codefixes/fixUnmatchedParameter.ts",
+ "codefixes/fixUnreferenceableDecoratorMetadata.ts",
"codefixes/fixUnusedIdentifier.ts",
"codefixes/fixUnreachableCode.ts",
"codefixes/fixUnusedLabel.ts",
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).js b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).js
new file mode 100644
index 0000000000000..83510c982892d
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).js
@@ -0,0 +1,108 @@
+//// [tests/cases/compiler/emitDecoratorMetadata_isolatedModules.ts] ////
+
+//// [type1.ts]
+interface T1 {}
+export type { T1 }
+
+//// [type2.ts]
+export interface T2 {}
+
+//// [class3.ts]
+export class C3 {}
+
+//// [index.ts]
+import { T1 } from "./type1";
+import * as t1 from "./type1";
+import type { T2 } from "./type2";
+import { C3 } from "./class3";
+declare var EventListener: any;
+
+class HelloWorld {
+ @EventListener('1')
+ handleEvent1(event: T1) {} // Error
+
+ @EventListener('2')
+ handleEvent2(event: T2) {} // Ok
+
+ @EventListener('1')
+ p1!: T1; // Error
+
+ @EventListener('1')
+ p1_ns!: t1.T1; // Ok
+
+ @EventListener('2')
+ p2!: T2; // Ok
+
+ @EventListener('3')
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+}
+
+
+//// [type1.js]
+"use strict";
+exports.__esModule = true;
+//// [type2.js]
+"use strict";
+exports.__esModule = true;
+//// [class3.js]
+"use strict";
+exports.__esModule = true;
+exports.C3 = void 0;
+var C3 = /** @class */ (function () {
+ function C3() {
+ }
+ return C3;
+}());
+exports.C3 = C3;
+//// [index.js]
+"use strict";
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = (this && this.__metadata) || function (k, v) {
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+exports.__esModule = true;
+var t1 = require("./type1");
+var class3_1 = require("./class3");
+var HelloWorld = /** @class */ (function () {
+ function HelloWorld() {
+ }
+ HelloWorld.prototype.handleEvent1 = function (event) { }; // Error
+ HelloWorld.prototype.handleEvent2 = function (event) { }; // Ok
+ HelloWorld.prototype.handleEvent3 = function (event) { return undefined; }; // Ok, Error
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [Object]),
+ __metadata("design:returntype", void 0)
+ ], HelloWorld.prototype, "handleEvent1");
+ __decorate([
+ EventListener('2'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [Object]),
+ __metadata("design:returntype", void 0)
+ ], HelloWorld.prototype, "handleEvent2");
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p1");
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p1_ns");
+ __decorate([
+ EventListener('2'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p2");
+ __decorate([
+ EventListener('3'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [class3_1.C3]),
+ __metadata("design:returntype", Object)
+ ], HelloWorld.prototype, "handleEvent3");
+ return HelloWorld;
+}());
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).symbols b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).symbols
new file mode 100644
index 0000000000000..075bdc3ee7822
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).symbols
@@ -0,0 +1,83 @@
+=== tests/cases/compiler/type1.ts ===
+interface T1 {}
+>T1 : Symbol(T1, Decl(type1.ts, 0, 0))
+
+export type { T1 }
+>T1 : Symbol(T1, Decl(type1.ts, 1, 13))
+
+=== tests/cases/compiler/type2.ts ===
+export interface T2 {}
+>T2 : Symbol(T2, Decl(type2.ts, 0, 0))
+
+=== tests/cases/compiler/class3.ts ===
+export class C3 {}
+>C3 : Symbol(C3, Decl(class3.ts, 0, 0))
+
+=== tests/cases/compiler/index.ts ===
+import { T1 } from "./type1";
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+import * as t1 from "./type1";
+>t1 : Symbol(t1, Decl(index.ts, 1, 6))
+
+import type { T2 } from "./type2";
+>T2 : Symbol(T2, Decl(index.ts, 2, 13))
+
+import { C3 } from "./class3";
+>C3 : Symbol(C3, Decl(index.ts, 3, 8))
+
+declare var EventListener: any;
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+class HelloWorld {
+>HelloWorld : Symbol(HelloWorld, Decl(index.ts, 4, 31))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ handleEvent1(event: T1) {} // Error
+>handleEvent1 : Symbol(HelloWorld.handleEvent1, Decl(index.ts, 6, 18))
+>event : Symbol(event, Decl(index.ts, 8, 15))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+ @EventListener('2')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ handleEvent2(event: T2) {} // Ok
+>handleEvent2 : Symbol(HelloWorld.handleEvent2, Decl(index.ts, 8, 28))
+>event : Symbol(event, Decl(index.ts, 11, 15))
+>T2 : Symbol(T2, Decl(index.ts, 2, 13))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ p1!: T1; // Error
+>p1 : Symbol(HelloWorld.p1, Decl(index.ts, 11, 28))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ p1_ns!: t1.T1; // Ok
+>p1_ns : Symbol(HelloWorld.p1_ns, Decl(index.ts, 14, 10))
+>t1 : Symbol(t1, Decl(index.ts, 1, 6))
+>T1 : Symbol(t1.T1, Decl(type1.ts, 1, 13))
+
+ @EventListener('2')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ p2!: T2; // Ok
+>p2 : Symbol(HelloWorld.p2, Decl(index.ts, 17, 16))
+>T2 : Symbol(T2, Decl(index.ts, 2, 13))
+
+ @EventListener('3')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+>handleEvent3 : Symbol(HelloWorld.handleEvent3, Decl(index.ts, 20, 10))
+>event : Symbol(event, Decl(index.ts, 23, 15))
+>C3 : Symbol(C3, Decl(index.ts, 3, 8))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+>undefined : Symbol(undefined)
+}
+
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).types b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).types
new file mode 100644
index 0000000000000..b2615eac81b73
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=commonjs).types
@@ -0,0 +1,86 @@
+=== tests/cases/compiler/type1.ts ===
+interface T1 {}
+export type { T1 }
+>T1 : T1
+
+=== tests/cases/compiler/type2.ts ===
+export interface T2 {}
+No type information for this code.
+No type information for this code.=== tests/cases/compiler/class3.ts ===
+export class C3 {}
+>C3 : C3
+
+=== tests/cases/compiler/index.ts ===
+import { T1 } from "./type1";
+>T1 : any
+
+import * as t1 from "./type1";
+>t1 : typeof t1
+
+import type { T2 } from "./type2";
+>T2 : T2
+
+import { C3 } from "./class3";
+>C3 : typeof C3
+
+declare var EventListener: any;
+>EventListener : any
+
+class HelloWorld {
+>HelloWorld : HelloWorld
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ handleEvent1(event: T1) {} // Error
+>handleEvent1 : (event: T1) => void
+>event : T1
+
+ @EventListener('2')
+>EventListener('2') : any
+>EventListener : any
+>'2' : "2"
+
+ handleEvent2(event: T2) {} // Ok
+>handleEvent2 : (event: T2) => void
+>event : T2
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ p1!: T1; // Error
+>p1 : T1
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ p1_ns!: t1.T1; // Ok
+>p1_ns : T1
+>t1 : any
+
+ @EventListener('2')
+>EventListener('2') : any
+>EventListener : any
+>'2' : "2"
+
+ p2!: T2; // Ok
+>p2 : T2
+
+ @EventListener('3')
+>EventListener('3') : any
+>EventListener : any
+>'3' : "3"
+
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+>handleEvent3 : (event: C3) => T1
+>event : C3
+>undefined! : undefined
+>undefined : undefined
+}
+
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).errors.txt b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).errors.txt
new file mode 100644
index 0000000000000..5e7f959a50696
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).errors.txt
@@ -0,0 +1,51 @@
+tests/cases/compiler/index.ts(9,23): error TS1272: A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+tests/cases/compiler/index.ts(15,8): error TS1272: A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+tests/cases/compiler/index.ts(24,28): error TS1272: A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+
+
+==== tests/cases/compiler/type1.ts (0 errors) ====
+ interface T1 {}
+ export type { T1 }
+
+==== tests/cases/compiler/type2.ts (0 errors) ====
+ export interface T2 {}
+
+==== tests/cases/compiler/class3.ts (0 errors) ====
+ export class C3 {}
+
+==== tests/cases/compiler/index.ts (3 errors) ====
+ import { T1 } from "./type1";
+ import * as t1 from "./type1";
+ import type { T2 } from "./type2";
+ import { C3 } from "./class3";
+ declare var EventListener: any;
+
+ class HelloWorld {
+ @EventListener('1')
+ handleEvent1(event: T1) {} // Error
+ ~~
+!!! error TS1272: A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+!!! related TS1376 tests/cases/compiler/index.ts:1:10: 'T1' was imported here.
+
+ @EventListener('2')
+ handleEvent2(event: T2) {} // Ok
+
+ @EventListener('1')
+ p1!: T1; // Error
+ ~~
+!!! error TS1272: A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+!!! related TS1376 tests/cases/compiler/index.ts:1:10: 'T1' was imported here.
+
+ @EventListener('1')
+ p1_ns!: t1.T1; // Ok
+
+ @EventListener('2')
+ p2!: T2; // Ok
+
+ @EventListener('3')
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+ ~~
+!!! error TS1272: A type referenced in a decorated signature must be imported with 'import type' or a namespace import when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+!!! related TS1376 tests/cases/compiler/index.ts:1:10: 'T1' was imported here.
+ }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).js b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).js
new file mode 100644
index 0000000000000..121f3be7031c6
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).js
@@ -0,0 +1,101 @@
+//// [tests/cases/compiler/emitDecoratorMetadata_isolatedModules.ts] ////
+
+//// [type1.ts]
+interface T1 {}
+export type { T1 }
+
+//// [type2.ts]
+export interface T2 {}
+
+//// [class3.ts]
+export class C3 {}
+
+//// [index.ts]
+import { T1 } from "./type1";
+import * as t1 from "./type1";
+import type { T2 } from "./type2";
+import { C3 } from "./class3";
+declare var EventListener: any;
+
+class HelloWorld {
+ @EventListener('1')
+ handleEvent1(event: T1) {} // Error
+
+ @EventListener('2')
+ handleEvent2(event: T2) {} // Ok
+
+ @EventListener('1')
+ p1!: T1; // Error
+
+ @EventListener('1')
+ p1_ns!: t1.T1; // Ok
+
+ @EventListener('2')
+ p2!: T2; // Ok
+
+ @EventListener('3')
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+}
+
+
+//// [type1.js]
+export {};
+//// [type2.js]
+export {};
+//// [class3.js]
+var C3 = /** @class */ (function () {
+ function C3() {
+ }
+ return C3;
+}());
+export { C3 };
+//// [index.js]
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = (this && this.__metadata) || function (k, v) {
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+import * as t1 from "./type1";
+import { C3 } from "./class3";
+var HelloWorld = /** @class */ (function () {
+ function HelloWorld() {
+ }
+ HelloWorld.prototype.handleEvent1 = function (event) { }; // Error
+ HelloWorld.prototype.handleEvent2 = function (event) { }; // Ok
+ HelloWorld.prototype.handleEvent3 = function (event) { return undefined; }; // Ok, Error
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [Object]),
+ __metadata("design:returntype", void 0)
+ ], HelloWorld.prototype, "handleEvent1");
+ __decorate([
+ EventListener('2'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [Object]),
+ __metadata("design:returntype", void 0)
+ ], HelloWorld.prototype, "handleEvent2");
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p1");
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p1_ns");
+ __decorate([
+ EventListener('2'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p2");
+ __decorate([
+ EventListener('3'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [C3]),
+ __metadata("design:returntype", Object)
+ ], HelloWorld.prototype, "handleEvent3");
+ return HelloWorld;
+}());
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).symbols b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).symbols
new file mode 100644
index 0000000000000..075bdc3ee7822
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).symbols
@@ -0,0 +1,83 @@
+=== tests/cases/compiler/type1.ts ===
+interface T1 {}
+>T1 : Symbol(T1, Decl(type1.ts, 0, 0))
+
+export type { T1 }
+>T1 : Symbol(T1, Decl(type1.ts, 1, 13))
+
+=== tests/cases/compiler/type2.ts ===
+export interface T2 {}
+>T2 : Symbol(T2, Decl(type2.ts, 0, 0))
+
+=== tests/cases/compiler/class3.ts ===
+export class C3 {}
+>C3 : Symbol(C3, Decl(class3.ts, 0, 0))
+
+=== tests/cases/compiler/index.ts ===
+import { T1 } from "./type1";
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+import * as t1 from "./type1";
+>t1 : Symbol(t1, Decl(index.ts, 1, 6))
+
+import type { T2 } from "./type2";
+>T2 : Symbol(T2, Decl(index.ts, 2, 13))
+
+import { C3 } from "./class3";
+>C3 : Symbol(C3, Decl(index.ts, 3, 8))
+
+declare var EventListener: any;
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+class HelloWorld {
+>HelloWorld : Symbol(HelloWorld, Decl(index.ts, 4, 31))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ handleEvent1(event: T1) {} // Error
+>handleEvent1 : Symbol(HelloWorld.handleEvent1, Decl(index.ts, 6, 18))
+>event : Symbol(event, Decl(index.ts, 8, 15))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+ @EventListener('2')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ handleEvent2(event: T2) {} // Ok
+>handleEvent2 : Symbol(HelloWorld.handleEvent2, Decl(index.ts, 8, 28))
+>event : Symbol(event, Decl(index.ts, 11, 15))
+>T2 : Symbol(T2, Decl(index.ts, 2, 13))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ p1!: T1; // Error
+>p1 : Symbol(HelloWorld.p1, Decl(index.ts, 11, 28))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ p1_ns!: t1.T1; // Ok
+>p1_ns : Symbol(HelloWorld.p1_ns, Decl(index.ts, 14, 10))
+>t1 : Symbol(t1, Decl(index.ts, 1, 6))
+>T1 : Symbol(t1.T1, Decl(type1.ts, 1, 13))
+
+ @EventListener('2')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ p2!: T2; // Ok
+>p2 : Symbol(HelloWorld.p2, Decl(index.ts, 17, 16))
+>T2 : Symbol(T2, Decl(index.ts, 2, 13))
+
+ @EventListener('3')
+>EventListener : Symbol(EventListener, Decl(index.ts, 4, 11))
+
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+>handleEvent3 : Symbol(HelloWorld.handleEvent3, Decl(index.ts, 20, 10))
+>event : Symbol(event, Decl(index.ts, 23, 15))
+>C3 : Symbol(C3, Decl(index.ts, 3, 8))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+>undefined : Symbol(undefined)
+}
+
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).types b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).types
new file mode 100644
index 0000000000000..b2615eac81b73
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules(module=esnext).types
@@ -0,0 +1,86 @@
+=== tests/cases/compiler/type1.ts ===
+interface T1 {}
+export type { T1 }
+>T1 : T1
+
+=== tests/cases/compiler/type2.ts ===
+export interface T2 {}
+No type information for this code.
+No type information for this code.=== tests/cases/compiler/class3.ts ===
+export class C3 {}
+>C3 : C3
+
+=== tests/cases/compiler/index.ts ===
+import { T1 } from "./type1";
+>T1 : any
+
+import * as t1 from "./type1";
+>t1 : typeof t1
+
+import type { T2 } from "./type2";
+>T2 : T2
+
+import { C3 } from "./class3";
+>C3 : typeof C3
+
+declare var EventListener: any;
+>EventListener : any
+
+class HelloWorld {
+>HelloWorld : HelloWorld
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ handleEvent1(event: T1) {} // Error
+>handleEvent1 : (event: T1) => void
+>event : T1
+
+ @EventListener('2')
+>EventListener('2') : any
+>EventListener : any
+>'2' : "2"
+
+ handleEvent2(event: T2) {} // Ok
+>handleEvent2 : (event: T2) => void
+>event : T2
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ p1!: T1; // Error
+>p1 : T1
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ p1_ns!: t1.T1; // Ok
+>p1_ns : T1
+>t1 : any
+
+ @EventListener('2')
+>EventListener('2') : any
+>EventListener : any
+>'2' : "2"
+
+ p2!: T2; // Ok
+>p2 : T2
+
+ @EventListener('3')
+>EventListener('3') : any
+>EventListener : any
+>'3' : "3"
+
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+>handleEvent3 : (event: C3) => T1
+>event : C3
+>undefined! : undefined
+>undefined : undefined
+}
+
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.errors.txt b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.errors.txt
new file mode 100644
index 0000000000000..cabda9caa7e94
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.errors.txt
@@ -0,0 +1,47 @@
+tests/cases/compiler/index.ts(8,23): error TS1267: A type referenced in a decorated signature must be imported with 'import type' when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+tests/cases/compiler/index.ts(14,8): error TS1267: A type referenced in a decorated signature must be imported with 'import type' when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+tests/cases/compiler/index.ts(20,28): error TS1267: A type referenced in a decorated signature must be imported with 'import type' when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+
+
+==== tests/cases/compiler/type1.ts (0 errors) ====
+ interface T1 {}
+ export type { T1 }
+
+==== tests/cases/compiler/type2.ts (0 errors) ====
+ export interface T2 {}
+
+==== tests/cases/compiler/class3.ts (0 errors) ====
+ export class C3 {}
+
+==== tests/cases/compiler/index.ts (3 errors) ====
+ import { T1 } from "./type1";
+ import type { T2 } from "./type2";
+ import { C3 } from "./class3";
+ declare var EventListener: any;
+
+ class HelloWorld {
+ @EventListener('1')
+ handleEvent1(event: T1) {} // Error
+ ~~
+!!! error TS1267: A type referenced in a decorated signature must be imported with 'import type' when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+!!! related TS1376 tests/cases/compiler/index.ts:1:10: 'T1' was imported here.
+
+ @EventListener('2')
+ handleEvent2(event: T2) {} // Ok
+
+ @EventListener('1')
+ p1!: T1; // Error
+ ~~
+!!! error TS1267: A type referenced in a decorated signature must be imported with 'import type' when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+!!! related TS1376 tests/cases/compiler/index.ts:1:10: 'T1' was imported here.
+
+ @EventListener('2')
+ p2!: T2; // Ok
+
+ @EventListener('3')
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+ ~~
+!!! error TS1267: A type referenced in a decorated signature must be imported with 'import type' when 'isolatedModules' and 'emitDecoratorMetadata' are enabled.
+!!! related TS1376 tests/cases/compiler/index.ts:1:10: 'T1' was imported here.
+ }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.js b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.js
new file mode 100644
index 0000000000000..bb5e71383f494
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.js
@@ -0,0 +1,99 @@
+//// [tests/cases/compiler/emitDecoratorMetadata_isolatedModules.ts] ////
+
+//// [type1.ts]
+interface T1 {}
+export type { T1 }
+
+//// [type2.ts]
+export interface T2 {}
+
+//// [class3.ts]
+export class C3 {}
+
+//// [index.ts]
+import { T1 } from "./type1";
+import type { T2 } from "./type2";
+import { C3 } from "./class3";
+declare var EventListener: any;
+
+class HelloWorld {
+ @EventListener('1')
+ handleEvent1(event: T1) {} // Error
+
+ @EventListener('2')
+ handleEvent2(event: T2) {} // Ok
+
+ @EventListener('1')
+ p1!: T1; // Error
+
+ @EventListener('2')
+ p2!: T2; // Ok
+
+ @EventListener('3')
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+}
+
+
+//// [type1.js]
+"use strict";
+exports.__esModule = true;
+//// [type2.js]
+"use strict";
+exports.__esModule = true;
+//// [class3.js]
+"use strict";
+exports.__esModule = true;
+exports.C3 = void 0;
+var C3 = /** @class */ (function () {
+ function C3() {
+ }
+ return C3;
+}());
+exports.C3 = C3;
+//// [index.js]
+"use strict";
+var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
+};
+var __metadata = (this && this.__metadata) || function (k, v) {
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
+};
+exports.__esModule = true;
+var class3_1 = require("./class3");
+var HelloWorld = /** @class */ (function () {
+ function HelloWorld() {
+ }
+ HelloWorld.prototype.handleEvent1 = function (event) { }; // Error
+ HelloWorld.prototype.handleEvent2 = function (event) { }; // Ok
+ HelloWorld.prototype.handleEvent3 = function (event) { return undefined; }; // Ok, Error
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [Object]),
+ __metadata("design:returntype", void 0)
+ ], HelloWorld.prototype, "handleEvent1");
+ __decorate([
+ EventListener('2'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [Object]),
+ __metadata("design:returntype", void 0)
+ ], HelloWorld.prototype, "handleEvent2");
+ __decorate([
+ EventListener('1'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p1");
+ __decorate([
+ EventListener('2'),
+ __metadata("design:type", Object)
+ ], HelloWorld.prototype, "p2");
+ __decorate([
+ EventListener('3'),
+ __metadata("design:type", Function),
+ __metadata("design:paramtypes", [class3_1.C3]),
+ __metadata("design:returntype", Object)
+ ], HelloWorld.prototype, "handleEvent3");
+ return HelloWorld;
+}());
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.symbols b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.symbols
new file mode 100644
index 0000000000000..c957b1781e3ea
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.symbols
@@ -0,0 +1,72 @@
+=== tests/cases/compiler/type1.ts ===
+interface T1 {}
+>T1 : Symbol(T1, Decl(type1.ts, 0, 0))
+
+export type { T1 }
+>T1 : Symbol(T1, Decl(type1.ts, 1, 13))
+
+=== tests/cases/compiler/type2.ts ===
+export interface T2 {}
+>T2 : Symbol(T2, Decl(type2.ts, 0, 0))
+
+=== tests/cases/compiler/class3.ts ===
+export class C3 {}
+>C3 : Symbol(C3, Decl(class3.ts, 0, 0))
+
+=== tests/cases/compiler/index.ts ===
+import { T1 } from "./type1";
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+import type { T2 } from "./type2";
+>T2 : Symbol(T2, Decl(index.ts, 1, 13))
+
+import { C3 } from "./class3";
+>C3 : Symbol(C3, Decl(index.ts, 2, 8))
+
+declare var EventListener: any;
+>EventListener : Symbol(EventListener, Decl(index.ts, 3, 11))
+
+class HelloWorld {
+>HelloWorld : Symbol(HelloWorld, Decl(index.ts, 3, 31))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 3, 11))
+
+ handleEvent1(event: T1) {} // Error
+>handleEvent1 : Symbol(HelloWorld.handleEvent1, Decl(index.ts, 5, 18))
+>event : Symbol(event, Decl(index.ts, 7, 15))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+ @EventListener('2')
+>EventListener : Symbol(EventListener, Decl(index.ts, 3, 11))
+
+ handleEvent2(event: T2) {} // Ok
+>handleEvent2 : Symbol(HelloWorld.handleEvent2, Decl(index.ts, 7, 28))
+>event : Symbol(event, Decl(index.ts, 10, 15))
+>T2 : Symbol(T2, Decl(index.ts, 1, 13))
+
+ @EventListener('1')
+>EventListener : Symbol(EventListener, Decl(index.ts, 3, 11))
+
+ p1!: T1; // Error
+>p1 : Symbol(HelloWorld.p1, Decl(index.ts, 10, 28))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+
+ @EventListener('2')
+>EventListener : Symbol(EventListener, Decl(index.ts, 3, 11))
+
+ p2!: T2; // Ok
+>p2 : Symbol(HelloWorld.p2, Decl(index.ts, 13, 10))
+>T2 : Symbol(T2, Decl(index.ts, 1, 13))
+
+ @EventListener('3')
+>EventListener : Symbol(EventListener, Decl(index.ts, 3, 11))
+
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+>handleEvent3 : Symbol(HelloWorld.handleEvent3, Decl(index.ts, 16, 10))
+>event : Symbol(event, Decl(index.ts, 19, 15))
+>C3 : Symbol(C3, Decl(index.ts, 2, 8))
+>T1 : Symbol(T1, Decl(index.ts, 0, 8))
+>undefined : Symbol(undefined)
+}
+
diff --git a/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.types b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.types
new file mode 100644
index 0000000000000..0048771bb4eac
--- /dev/null
+++ b/tests/baselines/reference/emitDecoratorMetadata_isolatedModules.types
@@ -0,0 +1,74 @@
+=== tests/cases/compiler/type1.ts ===
+interface T1 {}
+export type { T1 }
+>T1 : T1
+
+=== tests/cases/compiler/type2.ts ===
+export interface T2 {}
+No type information for this code.
+No type information for this code.=== tests/cases/compiler/class3.ts ===
+export class C3 {}
+>C3 : C3
+
+=== tests/cases/compiler/index.ts ===
+import { T1 } from "./type1";
+>T1 : any
+
+import type { T2 } from "./type2";
+>T2 : T2
+
+import { C3 } from "./class3";
+>C3 : typeof C3
+
+declare var EventListener: any;
+>EventListener : any
+
+class HelloWorld {
+>HelloWorld : HelloWorld
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ handleEvent1(event: T1) {} // Error
+>handleEvent1 : (event: T1) => void
+>event : T1
+
+ @EventListener('2')
+>EventListener('2') : any
+>EventListener : any
+>'2' : "2"
+
+ handleEvent2(event: T2) {} // Ok
+>handleEvent2 : (event: T2) => void
+>event : T2
+
+ @EventListener('1')
+>EventListener('1') : any
+>EventListener : any
+>'1' : "1"
+
+ p1!: T1; // Error
+>p1 : T1
+
+ @EventListener('2')
+>EventListener('2') : any
+>EventListener : any
+>'2' : "2"
+
+ p2!: T2; // Ok
+>p2 : T2
+
+ @EventListener('3')
+>EventListener('3') : any
+>EventListener : any
+>'3' : "3"
+
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+>handleEvent3 : (event: C3) => T1
+>event : C3
+>undefined! : undefined
+>undefined : undefined
+}
+
diff --git a/tests/cases/compiler/emitDecoratorMetadata_isolatedModules.ts b/tests/cases/compiler/emitDecoratorMetadata_isolatedModules.ts
new file mode 100644
index 0000000000000..e90af623cc12d
--- /dev/null
+++ b/tests/cases/compiler/emitDecoratorMetadata_isolatedModules.ts
@@ -0,0 +1,41 @@
+// @experimentalDecorators: true
+// @emitDecoratorMetadata: true
+// @isolatedModules: true
+// @module: commonjs,esnext
+
+// @Filename: type1.ts
+interface T1 {}
+export type { T1 }
+
+// @Filename: type2.ts
+export interface T2 {}
+
+// @Filename: class3.ts
+export class C3 {}
+
+// @Filename: index.ts
+import { T1 } from "./type1";
+import * as t1 from "./type1";
+import type { T2 } from "./type2";
+import { C3 } from "./class3";
+declare var EventListener: any;
+
+class HelloWorld {
+ @EventListener('1')
+ handleEvent1(event: T1) {} // Error
+
+ @EventListener('2')
+ handleEvent2(event: T2) {} // Ok
+
+ @EventListener('1')
+ p1!: T1; // Error
+
+ @EventListener('1')
+ p1_ns!: t1.T1; // Ok
+
+ @EventListener('2')
+ p2!: T2; // Ok
+
+ @EventListener('3')
+ handleEvent3(event: C3): T1 { return undefined! } // Ok, Error
+}
diff --git a/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata1.ts b/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata1.ts
new file mode 100644
index 0000000000000..40f9a7239a762
--- /dev/null
+++ b/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata1.ts
@@ -0,0 +1,46 @@
+///
+
+// @isolatedModules: true
+// @module: es2015
+// @experimentalDecorators: true
+// @emitDecoratorMetadata: true
+
+// @Filename: /mod.ts
+//// export default interface I1 {}
+//// export interface I2 {}
+
+// @Filename: /index.ts
+//// [|import { I2 } from "./mod";|]
+////
+//// declare var EventListener: any;
+//// class HelloWorld {
+//// @EventListener("1")
+//// p1!: I2;
+//// p2!: I2;
+//// }
+
+const diag = ts.Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled;
+
+goTo.file("/index.ts");
+
+verify.codeFix({
+ index: 0,
+ description: ts.Diagnostics.Convert_named_imports_to_namespace_import.message,
+ errorCode: diag.code,
+ applyChanges: false,
+ newFileContent: `import * as mod from "./mod";
+
+declare var EventListener: any;
+class HelloWorld {
+ @EventListener("1")
+ p1!: mod.I2;
+ p2!: mod.I2;
+}`,
+});
+
+verify.codeFix({
+ index: 1,
+ description: ts.Diagnostics.Convert_to_type_only_import.message,
+ errorCode: diag.code,
+ newRangeContent: `import type { I2 } from "./mod";`,
+});
diff --git a/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata2.ts b/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata2.ts
new file mode 100644
index 0000000000000..1ab14d1fc6a42
--- /dev/null
+++ b/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata2.ts
@@ -0,0 +1,38 @@
+///
+
+// @isolatedModules: true
+// @module: es2015
+// @experimentalDecorators: true
+// @emitDecoratorMetadata: true
+
+// @Filename: /mod.ts
+//// export default interface I1 {}
+//// export interface I2 {}
+
+// @Filename: /index.ts
+//// [|import I1, { I2 } from "./mod";|]
+////
+//// declare var EventListener: any;
+//// class HelloWorld {
+//// @EventListener("1")
+//// p1!: I2;
+//// p2!: I2;
+//// }
+
+const diag = ts.Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled;
+
+goTo.file("/index.ts");
+
+verify.codeFix({
+ description: ts.Diagnostics.Convert_named_imports_to_namespace_import.message,
+ errorCode: diag.code,
+ applyChanges: false,
+ newFileContent: `import I1, * as mod from "./mod";
+
+declare var EventListener: any;
+class HelloWorld {
+ @EventListener("1")
+ p1!: mod.I2;
+ p2!: mod.I2;
+}`,
+});
diff --git a/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata3.ts b/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata3.ts
new file mode 100644
index 0000000000000..7a7c66917c81e
--- /dev/null
+++ b/tests/cases/fourslash/codefixUnreferenceableDecoratorMetadata3.ts
@@ -0,0 +1,55 @@
+///
+
+// @isolatedModules: true
+// @module: es2015
+// @experimentalDecorators: true
+// @emitDecoratorMetadata: true
+
+// @Filename: /mod.ts
+//// export default interface I1 {}
+//// export interface I2 {}
+//// export class C1 {}
+
+// @Filename: /index.ts
+//// import I1, { I2 } from "./mod";
+////
+//// declare var EventListener: any;
+//// export class HelloWorld {
+//// @EventListener("1")
+//// p1!: I1;
+//// p2!: I2;
+//// }
+
+// @Filename: /index2.ts
+//// import { C1, I2 } from "./mod";
+////
+//// declare var EventListener: any;
+//// export class HelloWorld {
+//// @EventListener("1")
+//// p1!: I2;
+//// p2!: C1;
+//// }
+
+const diag = ts.Diagnostics.A_type_referenced_in_a_decorated_signature_must_be_imported_with_import_type_or_a_namespace_import_when_isolatedModules_and_emitDecoratorMetadata_are_enabled;
+
+goTo.file("/index.ts");
+verify.not.codeFixAvailable();
+
+// Mostly verifying that the type-only fix is not available
+// (if both were available you'd have to specify `index`
+// in `verify.codeFix`).
+goTo.file("/index2.ts");
+verify.codeFix({
+ description: ts.Diagnostics.Convert_named_imports_to_namespace_import.message,
+ errorCode: diag.code,
+ applyChanges: false,
+ newFileContent: `import * as mod from "./mod";
+
+declare var EventListener: any;
+export class HelloWorld {
+ @EventListener("1")
+ p1!: mod.I2;
+ p2!: mod.C1;
+}`,
+});
+