microsoft / microsoft/TypeScript

Use single-assignment variables for intermediate values needed in JS output for decorated classes

Open
#55,734 1 comment 0 reactions 1 assignee View on GitHub

@rbuckton is already working on this.

Since Sep 13, 2023.

Needs Investigation
Dominant language
Go
Stars
111k
Forks
14.3k
Avg merge
1d 19h
Merged PRs (30d)
117

Description

🔍 Search Terms

decorators reassigned inlining

✅ Viability Checklist
  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of our Design Goals: https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals
⭐ Suggestion

The key problem is that what was in the TS code simply class Foo { /* decorators used here */ } becomes something like this

var Foo_1;
let Foo = Foo_1 = class Foo {
  /* all references to Foo replaced with Foo_1 here */
};

Foo.staticProp = someValue;

// Second value assigned to Foo and Foo_1 after earlier references to them
// make it hard for a minimization tool to reason about these values.
Foo = Foo_1 = __decorate(...);

This is a problem for closure-compiler because logically Foo and Foo_1 could be treated as a constant after this point, but that's hard for the compiler to prove to itself because multiple assignments to these variables are made, and some references to them come before or between assignments.

If instead TS introduced temporary variables for the intermediate values and then assigned only the final result to the "real" variables from the original TS code which are used by all clients of the class, this would be a lot easier for closure-compiler and other tools to safely reason about.

For example:

var Foo;
let Foo_predecoration_1 = class {
  /* all references to Foo unchanged here */
};

Foo_predecoration_1.staticProp = someValue;

// Second value assigned to Foo and Foo_1 after earlier references to them
// make it hard for a minimization tool to reason about these values.
Foo = __decorate(...);

NOTE: This request seems to me very much in line with these stated TS design goals

  • Emit clean, idiomatic, recognizable JavaScript code.
  • Produce a language that is composable and easy to reason about.
📃 Motivating Example
  • This changed between versions 5.1 and 5.2

When decorators are used, variables that are assigned exactly once in the TS code end up getting multiple assignments, which makes optimization of the code by closure-compiler and probably other minimizers difficult.

This was true in 5.1, but got worse in 5.2 because it began replacing internal references to a class name with an alias variable.

TS 5.1: https://www.typescriptlang.org/play?experimentalDecorators=true&emitDecoratorMetadata=true&target=6&module=1&ts=5.1.6#code/KYDwDg9gTgLgBAbwL4G4BQaBmBXAdgYxgEsJc5cIIwARYfaAQxmgAoA6DhqAcwGcAuOA1wBPANoBdAJSIkGfABsGvXnABilRGjhxeMJkXxwAktTgBeOAHJoRbkVwMFV9Dr0GjpgEwX1lNqbo2rr6xEaYlCwyCME69Li8EArAbAoQ3CxWABLACmlWUq5wcsHxelDYhKwAAhRUtPRQTNBwYFBEAG5MwHBQwAwAJqQKInADdAAKUFSCuNgAtgBGwFC+AKzRJTqLXFFaOjoaEGwREFFFcaSJyanpmaaCVnAA1H7Hpi-WBUVyJbjAAHc3lE2DsoOc0EA

TS 5.2: https://www.typescriptlang.org/play?experimentalDecorators=true&emitDecoratorMetadata=true&target=6&module=1&ts=5.2.2#code/KYDwDg9gTgLgBAbwL4G4BQaBmBXAdgYxgEsJc5cIIwARYfaAQxmgAoA6DhqAcwGcAuOA1wBPANoBdAJSIkGfABsGvXnABilRGjhxeMJkXxwAktTgBeOAHJoRbkVwMFV9Dr0GjpgEwX1lNqbo2rr6xEaYlCwyCME69Li8EArAbAoQ3CxWABLACmlWUq5wcsHxelDYhKwAAhRUtPRQTNBwYFBEAG5MwHBQwAwAJqQKInADdAAKUFSCuNgAtgBGwFC+AKzRJTqLXFFaOjoaEGwREFFFcaSJyanpmaaCVnAA1H7Hpi-WBUVyJbjAAHc3lE2DsoOc0EA

💻 Use Cases
  1. What do you want to use this for?

    The change suggested here would enable better code minimization for closure-compiler and likely other JS-minimization tools.

  2. What shortcomings exist with current approaches?

    The multiple assignments prevent inlining of variable values and recognition of some values that should be safe to remove.

  3. What workarounds are you using in the meantime?

    No workaround exists now. We might try to specifically recognize this pattern as one generated by TS compiler and then make assumptions about the values being assigned, but that's more brittle than we'd like.

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.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.