Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

__setFunctionName breaks custom staticname on classes #62854

Open
Labels
BugA bug in TypeScriptHelp WantedYou can do this
Milestone
@miyaokamarina

Description

@miyaokamarina

🔎 Search Terms

__setFunctionName
class static name
ES decorators static name
__esDecorate static name

🕗 Version & Regression Information

5.0.4-5.9.3

⏯ Playground Link

https://tsplay.dev/WJgblw

💻 Code

constnoop=(Self:any,ctx:ClassDecoratorContext)=>{};constrand=()=>4;@noopexportdefaultclass{staticgetname(){return2434;}}(@noopclass{staticgetname(){return2434;}});(@noopclass__A{staticgetname(){return2434;}});@noopclass__B{staticgetname(){return2434;}}var__C= @noopclass{staticgetname(){return2434;}};var__D={[rand()]: @noopclass{staticgetname(){return2434;}}};// Unconditionally throws at runtime:@noopclass__E{static #a=2434;staticgetname(){returnthis.#a;}}// Undecorated classes are broken as well:var__F=class{staticgetname(){return2434;}// target≤es2021 => '__F'// target≥es2022 => 2434static{}}

🙁 Actual behavior

Staticname is overridden by__setFunctionName().

🙂 Expected behavior

Staticname should work as defined in the class code.

Additional information about the issue

Generated code for the ES decorators breaks custom staticname property on the decorated class. The only syntax that works is plainstatic name; field declaration; other kinds (methods,get/set/accessor) are broken.

The issue reproduces iff the compiler decides to inject thestatic { __setFunctionName(this, ...) } block, whichunconditionally overrides the staticname descriptor on the class object.

The issue also affects undecorated classes (when targeting older environments; see the examples).

I’m not sure whatexactly triggers the__setFunctionName() block injection. Sometimes it’s injected even if the class has a correct unambiguous automatic name. Sometimes itisn’t injected, even if the class becomes incorrectly named (e.g., when targetinges3/es5):

Missing `__setFunctionName()`

https://tsplay.dev/WKYAMN

// tests/cases/compiler/blockScopedVariablesUseBeforeDef.tsfunctionfoo8(){lety=class{a=x;};letx;//@ts-ignoreconsole.log(y.name);}// target≤es5    => 'class_###'// target≥es2015 => 'y'foo8();

But either way, it shadows non-field staticname declarations.

Possible Fix

Atruntime, check that the descriptor ofthis.name matches the automaticname descriptor shape (i.e.,value:string,writable≡enumerable≡false,configurable=true).The runtime check is necessary to correctly handle staticname declared with a computed key.

Technically, the necessary and sufficient condition is even simpler—just check forwritable≡false before__setFunctionName to robustly prevent overriding of non-field staticname declarations:

  • At this point, the descriptors are completely defined by the syntax:
    • Nostatic {} blocks evaluated.
    • No class decorators evaluated.
    • No class element initializers evaluated.
  • So, the staticname is one of:
    • Automatic,always defined. If there’s a staticnamefield, it’s to be reconfigured at the time of the actual field initialization.
    • Method.
    • get/set oraccessor.
  • Methods havewritable≡true.
  • get/set/accessor declarations havewritable≡undefined.

This matches the correct behavior:

  • With afieldstatic name declaration, it’s theautomaticname up to the time of the actualstatic name initialization. The field initialization successfully overrides the automatic descriptor.
  • For non-fields, the descriptor matches the declaration from the very beginning of the class. If thename is reconfigured here, the actual declaration doesn’t revert the override.

AdjustcreateClassNamedEvaluationHelperBlock() andisClassNamedEvaluationHelperBlock() innamedEvaluation.ts to produce a code like this:

static{Object.getOwnPropertyDescriptor(this,"name").writable===false&&__setFunctionName(this, ...);}

NB: Withtarget≤es5 anduseDefineForClassFields≡false, the compiler uses plainC.name=... assignment to set the staticname, which has no effect (doesn’t reconfigure the staticname descriptor), so the injected block—if injected—will call__setFunctionName()unconditionally. But this is already a compile-time error

Static property 'name' conflicts with built-in property'Function.name' of constructor function 'A'. (2699)

so it doesn’t matter here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptHelp WantedYou can do this

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp