Skip to content

getOwnPropertyNames(C.prototype) omits accessors and leaks a symbol key as the literal string "@@iterator" #9226

Description

@proggeramlug

Summary

For a class with an accessor and a symbol-keyed method, Object.getOwnPropertyNames on the prototype is wrong in two directions at once, and is internally inconsistent with getOwnPropertyDescriptor.

class C {
  m() {}
  get g() { return 1; }
  set s(v) {}
  [Symbol.iterator]() {}
}

Object.getOwnPropertyNames(C.prototype)
// node:  ["constructor", "g", "m", "s"]
// perry: ["@@iterator", "constructor", "m"]

Object.getOwnPropertySymbols(C.prototype).length   // node: 1    perry: 0
Reflect.ownKeys(C.prototype).length                // node: 5    perry: 3

Three distinct defects:

  1. Accessors are missingg and s do not appear at all.
  2. A symbol key leaks into the string list as the literal "@@iterator", where it should appear only in getOwnPropertySymbols.
  3. getOwnPropertySymbols returns nothing, so the symbol is not merely misfiled — it is absent from the list it belongs in.

Internally inconsistent

The information is present; only the enumeration is wrong:

Object.prototype.hasOwnProperty.call(C.prototype, "g")   // true
Object.getOwnPropertyDescriptor(C.prototype, "g")        // the accessor descriptor

So this is an own-keys enumeration bug on class prototypes, not a missing property.

Impact

Silent and structural. Anything that reflects over a class prototype — decorators, DI containers, serializers, mixin/Object.assign-based composition, test frameworks discovering methods — sees a wrong key set: accessors vanish, and a "@@iterator" string appears that no correct program expects. Because hasOwnProperty and getOwnPropertyDescriptor disagree with the enumeration, a two-step "list then inspect" pattern gives self-contradictory results.

How it was found

A 104-assertion differential over class prototypes, run against node --experimental-strip-types on unmodified main (84185b5656) as a control before landing an unrelated change. It surfaced 8 pre-existing divergences; this is the sharpest of them. Minimal repro above; the full harness is on the #9214 branch.

Not related to #9214, #9192 or #9219 — reproduces on pristine main.

Fix direction

The own-keys enumeration for class prototypes needs to (a) include accessor-backed entries, (b) route symbol keys to getOwnPropertySymbols rather than stringifying them into the names list, and (c) keep Reflect.ownKeys as the union in spec order — integer-like keys ascending, then strings in insertion order, then symbols in insertion order. Whatever produces the "@@iterator" spelling is the tell: an internal symbol representation is reaching a string-key path unconverted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions