Skip to content

fix: private @observable accessor fields with the same name in a class and its subclass share one value - #4774

Open
gesposito wants to merge 1 commit into
mobxjs:mainfrom
gesposito:fix/private-decorated-member-keys
Open

gesposito wants to merge 1 commit into
mobxjs:mainfrom
gesposito:fix/private-decorated-member-keys

Conversation

@gesposito

Copy link
Copy Markdown
Contributor

What / why

context.name of a private member is only its description, like "#value". The 2022.3 @observable and @computed decorators use it as the key in the administration, so two separate private members that happen to have the same name, one on a class and one on its subclass, end up under one key:

class Parent {
    @observable accessor #value = 1
    get parentValue() {
        return this.#value
    }
}

class Child extends Parent {
    @observable accessor #value = 2
    get childValue() {
        return this.#value
    }
}

const child = new Child()
child.parentValue // 2, expected 1

A write to the parent's field changes the subclass's field as well. A private @observable accessor on the parent and a private @computed getter with the same name on the subclass collide the same way: the parent's field returns the computed value.

Private members now get a key of their own, a symbol that carries the name as its description. Public members keep context.name. Debug names are unchanged (Store@1.#value).

Behavior change

A private member could not be addressed reliably by its name before, because the name is not unique per object. Now it cannot be addressed by name at all: isObservableProp(obj, "#value"), getAtom(obj, "#value") and observe(obj, "#value", ...) no longer find it, and the change events of a private field that object-level observe and spy receive carry the symbol as name. toJS already left private fields out.

Tests

Code change checklist

  • Added/updated unit tests
  • Updated /docs: no documented behavior changes
  • Verified that there is no significant performance drop (npm -w mobx run test:performance): only the key of private members changes, the read and write paths are the same

`context.name` of a private member is only its description, like "#value".
The 2022.3 `@observable` and `@computed` decorators used it as the key in the
administration, so a class and its subclass that both declare a private member
with that name shared one entry: the parent's `#value` read and wrote the
subclass's value.

Private members are now kept under a symbol of their own. Debug names are
unchanged.
@changeset-bot

changeset-bot Bot commented Nov 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d1ddc46

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
mobx Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant