Skip to content

JavaScript: named class expressions lack class/member structure and inheritance #2499

Description

@Puma7

Named JS/TS class expressions lack class/member structure and inheritance. Reproduced on v1.6.2 and source main fc0da38f, without a framework:

class Base { run() { return 1; } }
function register(Type) { return Type; }
register(class Widget extends Base {
  run() { return super.run(); }
});

Expected: a Widget class, contained Widget::run method and inheritance to Base. Actual: only Base is a class; some expression methods become free functions. This is missing ownership/structure, not loss of every body call. The equivalent class declaration works. Variable initializers and custom-element registration reproduce the expression gap too.

A fix must preserve JavaScript scope:

register(class Widget {});
new Widget(); // ReferenceError: the expression's inner name is not an outer binding

Adding the missing class without guarding its inner name creates false targets outside the expression, including from Vue/Svelte scripts. A real same-named outer class or constant must remain usable.

Draft #2500 updates both WASM and native TS/JS extraction, retains class-header signatures through persistence, and gates expression targets. This does not infer arbitrary class-value flow or fix the separate super resolution gap in #2497.

Validation: 32 expression/scope cases and 120 selected native/WASM parity cases pass on Windows/Node 24; Ruby and multi-language node-identity controls are included. No database schema or kernel ABI change is needed.

Activity

  1. changed the title [-]JavaScript: named class expressions inside customElements.define lose classes and methods[/-] [+]JavaScript: named class expressions lose class and method definitions[/+] on Oct 11, 2026
  2. changed the title [-]JavaScript: named class expressions lose class and method definitions[/-] [+]JavaScript: named class expressions lack class/member structure and inheritance[/+] on Oct 12, 2026
  3. Puma7 commented on Oct 12, 2026

    @Puma7
    Author

    Updated validation after the supplied review:

    The issue remains missing class/member structure, not all body calls. #2500 retains inner-name scope protection: removing it creates targets where JavaScript raises ReferenceError and can steal a real outer binding. The current native build passes all 152 expression/scope/parity cases. Broader class-value propagation remains outside the patch.

  4. colbymchenry commented on Oct 23, 2026

    @colbymchenry
    Owner

    Thanks for the clear report and the scope example, @Puma7!

    #2825 is merged to main. A named class expression is now indexed as a class in both engines, with its methods, fields and the class it extends. So this, super and static calls inside it link the way a declaration's do; super calls go through the matcher from #2818.

    Its name stays scoped as you described: new Widget() outside the expression links nothing, and a same-named outer class or constant keeps its links. A class that a CommonJS module exports, like module.exports = class Router {…}, is reached through require just like a declaration.

    Class values that travel any other way, such as a factory's return value, still aren't followed. It ships in the next release, and a re-index picks it up.

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions