From bdacbe3f606eca45e50f36d3137a9c77b3614ca9 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 28 Apr 2021 09:57:58 -0700 Subject: [PATCH 1/3] Add test --- .../decoratorMetadataWithTypeOnlyImport2.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/cases/conformance/decorators/decoratorMetadataWithTypeOnlyImport2.ts diff --git a/tests/cases/conformance/decorators/decoratorMetadataWithTypeOnlyImport2.ts b/tests/cases/conformance/decorators/decoratorMetadataWithTypeOnlyImport2.ts new file mode 100644 index 0000000000000..c63fcf1a162d6 --- /dev/null +++ b/tests/cases/conformance/decorators/decoratorMetadataWithTypeOnlyImport2.ts @@ -0,0 +1,17 @@ +// @experimentalDecorators: true +// @emitDecoratorMetadata: true + + +// @filename: services.ts +export namespace Services { + export class Service {} +} + +// @filename: index.ts +import type { Services } from './services'; + +declare const decorator: any; +export class Main { + @decorator() + field: Services.Service; +} From bbdcb00532e00b674be9b0f5881f49627f364cdf Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Tue, 6 Jul 2021 13:05:00 -0600 Subject: [PATCH 2/3] Fix metadata references to type-only-imported namespaces --- src/compiler/checker.ts | 7 ++- .../decoratorMetadataWithTypeOnlyImport2.js | 53 +++++++++++++++++++ ...coratorMetadataWithTypeOnlyImport2.symbols | 27 ++++++++++ ...decoratorMetadataWithTypeOnlyImport2.types | 27 ++++++++++ 4 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.js create mode 100644 tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.symbols create mode 100644 tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.types diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d8d282086fdc4..0f46c61ed8685 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -40348,9 +40348,14 @@ namespace ts { } // Resolve the symbol as a value to ensure the type can be reached at runtime during emit. + let isTypeOnly = false; + if (isQualifiedName(typeName)) { + const rootValueSymbol = resolveEntityName(getFirstIdentifier(typeName), SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); + isTypeOnly = rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration) || false; + } const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - const isTypeOnly = valueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration) || false; const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; + isTypeOnly ||= valueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration) || false; // Resolve the symbol as a type so that we can provide a more useful hint for the type serializer. const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location); diff --git a/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.js b/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.js new file mode 100644 index 0000000000000..54af1f87a20bd --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.js @@ -0,0 +1,53 @@ +//// [tests/cases/conformance/decorators/decoratorMetadataWithTypeOnlyImport2.ts] //// + +//// [services.ts] +export namespace Services { + export class Service {} +} + +//// [index.ts] +import type { Services } from './services'; + +declare const decorator: any; +export class Main { + @decorator() + field: Services.Service; +} + + +//// [services.js] +"use strict"; +exports.__esModule = true; +exports.Services = void 0; +var Services; +(function (Services) { + var Service = /** @class */ (function () { + function Service() { + } + return Service; + }()); + Services.Service = Service; +})(Services = exports.Services || (exports.Services = {})); +//// [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; +exports.Main = void 0; +var Main = /** @class */ (function () { + function Main() { + } + __decorate([ + decorator(), + __metadata("design:type", Function) + ], Main.prototype, "field"); + return Main; +}()); +exports.Main = Main; diff --git a/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.symbols b/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.symbols new file mode 100644 index 0000000000000..42c4492e1b71c --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.symbols @@ -0,0 +1,27 @@ +=== tests/cases/conformance/decorators/services.ts === +export namespace Services { +>Services : Symbol(Services, Decl(services.ts, 0, 0)) + + export class Service {} +>Service : Symbol(Service, Decl(services.ts, 0, 27)) +} + +=== tests/cases/conformance/decorators/index.ts === +import type { Services } from './services'; +>Services : Symbol(Services, Decl(index.ts, 0, 13)) + +declare const decorator: any; +>decorator : Symbol(decorator, Decl(index.ts, 2, 13)) + +export class Main { +>Main : Symbol(Main, Decl(index.ts, 2, 29)) + + @decorator() +>decorator : Symbol(decorator, Decl(index.ts, 2, 13)) + + field: Services.Service; +>field : Symbol(Main.field, Decl(index.ts, 3, 19)) +>Services : Symbol(Services, Decl(index.ts, 0, 13)) +>Service : Symbol(Services.Service, Decl(services.ts, 0, 27)) +} + diff --git a/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.types b/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.types new file mode 100644 index 0000000000000..5667222fda9dc --- /dev/null +++ b/tests/baselines/reference/decoratorMetadataWithTypeOnlyImport2.types @@ -0,0 +1,27 @@ +=== tests/cases/conformance/decorators/services.ts === +export namespace Services { +>Services : typeof Services + + export class Service {} +>Service : Service +} + +=== tests/cases/conformance/decorators/index.ts === +import type { Services } from './services'; +>Services : any + +declare const decorator: any; +>decorator : any + +export class Main { +>Main : Main + + @decorator() +>decorator() : any +>decorator : any + + field: Services.Service; +>field : Services.Service +>Services : any +} + From 0f0163338c49cdfbc62c459a20c0700b31298f1b Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 2 Aug 2021 12:37:15 -0700 Subject: [PATCH 3/3] Use `!!` instead of `|| false` --- 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 0f46c61ed8685..a4be4f67a3990 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -40351,11 +40351,11 @@ namespace ts { let isTypeOnly = false; if (isQualifiedName(typeName)) { const rootValueSymbol = resolveEntityName(getFirstIdentifier(typeName), SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); - isTypeOnly = rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration) || false; + isTypeOnly = !!rootValueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); } const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ true, location); const resolvedSymbol = valueSymbol && valueSymbol.flags & SymbolFlags.Alias ? resolveAlias(valueSymbol) : valueSymbol; - isTypeOnly ||= valueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration) || false; + isTypeOnly ||= !!valueSymbol?.declarations?.every(isTypeOnlyImportOrExportDeclaration); // Resolve the symbol as a type so that we can provide a more useful hint for the type serializer. const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location);