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

Suggestion: support compile time annotations alongside runtime decorators #30723

Open
EdwardDrapkin opened this issue Apr 2, 2019 · 5 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@EdwardDrapkin
Copy link

EdwardDrapkin commented Apr 2, 2019

Search Terms

annotation
compile time decorator

Suggestion

The way that decorators are currently implemented in TypeScript mirrors their functionality in JS in that they exist at run time and work on run time objects. Because of TypeScript's transpiled nature, a tremendous amount of important metadata is lost by the time decorators are run. Even with the reflect-metadata package, important type information is lost. This represents a nearly insurmountable hurdle in developing high quality software in some extremely important areas.

Consider the case of dependency injection. Any of the TS containers require manually wiring the container together and, even worse, a healthy amount of invocation-site syntactical noise. I come from a Java background, and I think about the Spring DI container, where there is no manual configuration and there is no invocation-site noise, because there's no invocation site. The container is constructed at compile time based on annotations and classpath discovery, which leads to a much smoother developer experience. Building a DI container in TS with that level of developer ergonomics would be a pretty herculean task.

Consider the case of automatically generating webservice code from static model definitions. I'm not even sure if this is currently possible, but it's a feature that developers coming from mature web frameworks expect.

I believe that these two things, as well as a myriad of other cases where AOP is well applied, are important pieces that should be available in the TS ecosystem. TS is a compiled language and constraining the metaprogramming (decorator) facilities to what is available in JS code prevents these tools from being developed, or at least greatly slows their progress.

To this aim, I would like to suggest the addition of compiler annotations: functions that run on compiler nodes at compile time, have the ability to output additional code and otherwise interact with the compiler, but do not have the ability to mutate the compiler nodes. These suggested annotations would only ever be compile-time metadata, whereas decorators are run-time mutators. Adding or removing decorators will change run time behavior, but annotated code should always compile to the same code whether annotations are added or removed. Annotated code may inform a framework that other code is to be generated, but are otherwise completely erased in the JS code and exist only as a compiler facility.

I believe it's fully possible to do all of this now with a custom compiler step that outputs generated code, and it may even be possible to integrate with the language server so that code doesn't have to constantly be generated. I don't believe this violates any of the design goals/non-goals of TS, as the annotations don't change the behavior (or emitted JS) of the annotated code, merely provide an easier facility for library developers to interact with TS and take advantage of the compile step.

I don't want to presume to recommend a syntax or an API to this feature.

To summarize, annotations would:

  • Only exist at compile time and be entirely erased by the compiler
  • Interact with the compiler directly, having access to the compiler node and API
  • Be able to output additional code to be compiled as part of the currently-running compile step
  • Be attachable to (almost?) any node, but have to declare what they can accept (e.g. an annotation for DisableLint would be allowed anywhere, but a Injectable annotation would likely want to narrow its scope)
@RyanCavanaugh
Copy link
Member

Duplicate #2900?

@EdwardDrapkin
Copy link
Author

EdwardDrapkin commented Apr 3, 2019

It's a similar suggestion, but of a much smaller scope.

In my mind, annotations should be attachable to almost anything that is a compiler node: a class, a function, a class field, a local variable, an interface, a field assignment, etc.

An example of something that I think this would make much easier than is currently possible that the other suggestion wouldn't necessarily help with: Let's say you're working in a large hypothetical framework and have an interface hierarchy of Animal > FourLegs > Canine > Dog > GermanShepherd. In one of your controllers, you ask for an Animal from the framework. With annotations, you could annotate class Fluffy implements GermanShepherd and allow the framework to register the class as a qualifying injection for that entire hierarchy and provide you Fluffy.

Another case: adding a SinceVersion, Commercial, IEOnly, whatever annotations to source code and building a tool to compile separate SDKs for different targets from the same code.

It doesn't appear that the other suggestion would enable this, because it doesn't mention that the functions are specifically tied to the compiler API and can potentially output new code to be compiled in the same compile step. Maybe I should be more clear in the original issue, I will clarify.

@RyanCavanaugh RyanCavanaugh added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Apr 16, 2019
@Mart-Bogdan
Copy link

I belive this is great, as way to perform custom code transformations at compile time, not at runtime!

By the way, to circumvent the limitation of reflection we could make TS compiler to inject JS annotations with type information?

@devhid
Copy link

devhid commented Aug 24, 2022

Hey, any update on this? Would be great to have this.

@hydroper
Copy link

#54672

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants