Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

emitDecoratorMetadata causes runtime errors by referencing type-only imports with namespaces #42624

Closed
liorcode opened this issue Feb 3, 2021 · 6 comments · Fixed by #44915
Closed
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@liorcode
Copy link

liorcode commented Feb 3, 2021

Bug Report

Related to #37672 and #39337 - seems this bug still happens if class is wrapped by a namespace.

🔎 Search Terms

emitDecoratorMetadata, type-only imports, decorators

🕗 Version & Regression Information

Typescript 4.1.3, Typescript 4.2.0 beta

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about emitDecoratorMetadata and type-only imports

⏯ Playground Link

Workbench Repro

💻 Code

// @experimentalDecorators
// @emitDecoratorMetadata
// @strict: false


// @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;
}

🙁 Actual behavior

Typescript will reference "Services.Service" even though it's not imported (only the type was). This will crash in runtime:

__decorate([
decorator(),
__metadata("design:type", Services.Service)
], Main.prototype, "field", void 0);

🙂 Expected behavior

Should not reference non imported classes:

__decorate([
decorator(),
__metadata("design:type", Object)
], Main.prototype, "field", void 0);

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Feb 5, 2021
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.3.0 milestone Feb 5, 2021
@RyanCavanaugh
Copy link
Member

I could be convinced that this should be a compile-time error rather than emitting Object. Thoughts?

@andrewbranch
Copy link
Member

It seems like it should be an error to me. But the same would apply to #37672@rbuckton is there a reason we wouldn’t want to have an error here?

@rbuckton
Copy link
Member

rbuckton commented Feb 6, 2021

It seems at first glance like a good idea to report an error, but why should importing the type (only) of a class be any different than importing an interface and using the exact same syntax. Also, this works just fine:

import type { Services } from './services';
type S = Services.Service;

declare const decorator: any;
export class Main {
  @decorator()
  field: S;
}

So if we can use an alias or an interface, why not an import type { ... }?

I think we should treat a type-only import the same way we do an interface or type alias and just emit Object.

@liorcode
Copy link
Author

liorcode commented Feb 8, 2021

Not sure I understand though, why should it be a compile-time error?

@andrewbranch
Copy link
Member

I guess it depends on how important it is for the metadata to be as complete as it could be. The thought is simply that using import type here is probably a mistake, since you get better metadata just be deleting the type keyword, but the discoverability of that mistake seems super low. There is likely no reason why the user shouldn’t just be using a regular import here. But if you think the importance of the metadata is low, maybe it’s not worthwhile to error.

@liorcode
Copy link
Author

liorcode commented Feb 9, 2021

Well, in my use case I'm importing a package using a type-only import to make sure it doesn't get bundled, since I want the bundle to be minimal. So I definitely don't want to change it to a regular import.
And actually for this file I don't really care about the metadata (I actually don't need the metadata at all in this specific file, but since I have a single tsconfig in this app, I can't control which files get it or not..).
For now, as a workaround, I just use a type alias and then it gets emitted as Object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants