microsoft / microsoft/TypeScript

Suggestion: support compile time annotations alongside runtime decorators

Open
#30,723 5 comments 48 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Awaiting More Feedback Suggestion
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
2d 4h
Merged PRs (30d)
132

Description

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)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names no files, tests, or concrete entry points. Start by reviewing the existing decorator implementation, compiler-node and compiler-API surfaces, and language-server integration; done would require a settled syntax and API for compile-time annotations that are erased from emitted JavaScript while supporting generated code.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.