Skip to content

--experimentalDecorators: leading comment on a decorated constructor parameter is emitted in JS output (tsc drops it) #64436

Description

🔎 Search Terms

experimentalDecorators, parameter decorator, comment, JSDoc, emit, legacy decorators, visitParameterDeclaration

🕗 Version & Regression Information

  • This is the behavior in every version I tried: the playground's current nightly and tsgo built from main at df1a31e6d5.
  • tsc 6.0.3 does not emit the comment.

⏯ Playground Link

https://tsgo.sxzz.dev/#eNplUMFKAzEQ/ZUhp7YsWykiuF4Ee1EQwetuD2l2tkayScgktVL67042VKo9JTPv5b2XdxSDaNpWjFLbOpKoRI/KyIAwJKuidhZ4MavrWoYdNSDtd7uZT+dDZzuLB+9CBH5CBE9w7CyAcpZiSCq6MMszwHKxgMcefUAlI/aQCMHFDwywWBYGo4qdfAM2jVsMczieOnsSm6oVkVhx0Lv6k5zlhJNJJ5QbvTYY3nyOSZ1oin3GIqfFmFedQOKUfK/O4Oj6ZLCAHIkw7Hn6B78jOZOyciFuk+3Z7ILHf9Rq8uDP4u8a6XUSeLYRg/NXuEtxrVkni/aaLoOV6uXZ9M8zzunMHl+4gqJ/bXzwGPSINkqzRuVYyIWplkzLrNLophJKNIKL3POxulnd1ff16pbnL9EM0hCefgDD4a0/

💻 Code

declare function dec(...args: any[]): any;

export class C {
  constructor(
    /** @deprecated use other */
    @dec dep: number) {}
}

with "experimentalDecorators": true.

🙁 Actual behavior

The constructor is emitted with the parameter's comment:

    constructor(
    /** @deprecated use other */
    dep) { }

🙂 Expected behavior

Same as tsc 6.0.3, which drops the comment:

    constructor(dep) { }

(The class wrapper also differs between the two compilers, export class C vs let C = class C with C = __decorate(...); that's not what this issue is about.)

Additional information about the issue

This matters for tools that read JSDoc from the emitted JS: a JSDoc block that ends up on a bare parameter name gets parsed in a position it wasn't written for.

The transformer is not where the two compilers differ: Strada's visitParameterDeclaration in legacyDecorators.ts also calls setCommentRange(updated, node) with the original range, the same as tsgo. So the actual difference must be further downstream, presumably in how the printer emits comments for that range. We haven't found it.

As a local workaround, we set the comment range to the range already moved past the decorators, which gives the same output as tsc:

  if updated != node.AsNode() {
-   // While we emit the source map for the node after skipping decorators and modifiers,
-   // we need to emit the comments for the original range.
-   tx.EmitContext().SetCommentRange(updated, node.Loc)
    newLoc := transformers.MoveRangePastModifiers(node.AsNode())
    updated.Loc = newLoc
+   tx.EmitContext().SetCommentRange(updated, newLoc)
    tx.EmitContext().SetSourceMapRange(updated, newLoc)
    tx.EmitContext().SetEmitFlags(updated.Name(), printer.EFNoTrailingSourceMap)
  }

That's a deviation from Strada's transformer, so it may not be the right upstream fix.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Not a DefectThis behavior is one of several equally-correct options

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions