From bfd5b2f7f09e95da708260c5b386a8987bd381f4 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Mon, 2 Aug 2021 14:18:15 -0700 Subject: [PATCH] Fix decorator metadata references to type-only-imported namespaces (#44915) * Add test * Fix metadata references to type-only-imported namespaces * Use `!!` instead of `|| false` --- src/compiler/checker.ts | 7 ++- .../decoratorMetadataWithTypeOnlyImport2.js | 53 +++++++++++++++++++ ...coratorMetadataWithTypeOnlyImport2.symbols | 27 ++++++++++ ...decoratorMetadataWithTypeOnlyImport2.types | 27 ++++++++++ .../decoratorMetadataWithTypeOnlyImport2.ts | 17 ++++++ 5 files changed, 130 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 create mode 100644 tests/cases/conformance/decorators/decoratorMetadataWithTypeOnlyImport2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b96d0462e132c..a5809854fee15 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -40480,9 +40480,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); + } 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); // 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 +} + 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; +}