Skip to content

tc39-transfer/proposal-object-get-non-index-string-properties

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Object.getNonIndexStringProperties()

Champions / Authors

  • Ruben Bridgewater – Datadog, Node.js TSC
  • Jordan Harband - HeroDevs, TC39 delegate

Motivation

JavaScript objects—including Arrays, TypedArrays, and array‑like objects—can have own enumerable string‑named properties that are not numeric indices. Extracting those property names today typically falls back to verbose index‑detection filters on Object.keys:

Object.keys(arr) // Enumerable properties only
  .filter(key => !(/^0|([1-9]\d*)$/.test(key) && +key < 2 ** 32 - 1));

Object.getNonIndexStringProperties standardizes this task, returning an array of enumerable, non‑index string keys in the same order as Object.keys while removing hand‑rolled index checks.

This should be much much faster overall and easier to follow in code. It is needed in all cases where correctness is important.

Prior Art & Alternatives

  • Python’s list.__dict__ exposes non‑index attributes but only those that are publicly accessible.
  • A variant returning both enumerable and non‑enumerable keys was considered, but this proposal intentionally limits itself to enumerable keys to keep semantics simple and predictable.

Proposed API

declare namespace Object {
  /**
   * Return an array of the target’s **enumerable** own property names that are
   * strings and **not array indices**.
   */
  function getNonIndexStringProperties(target: any): string[];
}
  • target – Converted to an object via ToObject.
  • Result – An array containing the target’s own keys that:
    • are of type string;
    • are enumerable ([[Enumerable]] is true);
    • are not array indices (IsArrayIndex is false);

Illustrative Examples

const a = [1, 2, 3];
a.description = "coords";
Object.defineProperty(a, "secret", {
  value: true,
  enumerable: false,
});
a[5] = 42;

Object.getNonIndexStringProperties(a);
// ["description"] ("secret" is non‑enumerable)

Object.getNonIndexStringProperties({ foo: 1, bar: 2 });
// ["foo", "bar"] (works on any object)

// TypedArray example
const ta = new Uint8Array(2);
ta.meta = "payload";
Object.getNonIndexStringProperties(ta);
// ["meta"] (excludes "0", "1" which are indices)

// Array-like example
const arrayLike = {0: 'a', 1: 'b', length: 2, note: 'x'};
Object.getNonIndexStringProperties(arrayLike);
// ["note"] (excludes "0", "1" when enumerable)

Polyfill (Spec‑Compliant)

Object.getNonIndexStringProperties = function getNonIndexStringProperties (target) {
  function isArrayIndex(key) {
    return /^0|([1-9]\d*)$/.test(key) && +key < 2 ** 32 - 1;
  }
  const o = Object(target);
  const keys = [];
  for (const key of Object.keys(o)) { // enumerable names only
    if (isArrayIndex(key)) continue;
    keys.push(key);
  }
  return keys;
};

Draft Specification Text

New abstract operation

EnumerableNonIndexStringKeys ( O )

  1. Assert: O is an Object.
  2. Let keys be an empty list.
  3. For each element key of ? O.[[OwnPropertyKeys]]() in list order, do
    1. If key is a Symbol, continue.
    2. If IsArrayIndex(key) is true, continue.
    3. Let desc be ? O.[[GetOwnProperty]](k).
    4. If desc.[[Enumerable]] is false, continue.
    5. Append key to keys.
  4. Return CreateArrayFromList(keys).

New built‑in function

Object.getNonIndexStringProperties ( target )

  1. Let O be ? ToObject(target).
  2. Let result be EnumerableNonIndexStringKeys(O).
  3. Return result.

Arrays vs TypedArrays: index upper bound and semantics

  • Arrays: A property key is an array index if it is a String whose numeric value is an integer in the inclusive range 0 … 2³²−2. Thus, for Arrays, keys like "4294967294" are indices, while "4294967295" is not and remains a non‑index string property.
  • TypedArrays: Typed arrays are integer‑indexed exotic objects. Only indices in the range 0 … length − 1 exist, and they use canonical numeric index strings. Out‑of‑bounds numeric keys (e.g., "999") are not own properties at all and cannot be created as ordinary data properties. As a result, enumeration yields only in‑range indices, which this operation excludes.

This difference means the filter excludes:

  • For Arrays: all keys considered array indices by the 0 … 2³²−2 rule.
  • For TypedArrays: all in‑range canonical numeric indices 0 … length − 1 (none outside that range can appear).

Placement Rationale

Locating the function on Object maximizes applicability and aligns with existing enumeration APIs (e.g., Object.keys). It:

  • Works uniformly for Arrays, TypedArrays, and array‑like objects.
  • Reduces conceptual friction by pairing with Object.keys (which provides the iteration order we filter).
  • Avoids multiple entry points for the same operation.

For background on index semantics and related discussions, see tc39/proposal‑object‑property‑count#5.

Alternative: keep on Array, but cover array‑like objects

If the committee prefers to keep the function on Array, an alternative path would be:

  • Accept any target and apply ToObject unconditionally.
  • Use the same enumeration and filtering rules described in this proposal.
  • Specify that the operation works on array‑like objects (and TypedArrays) as input, even though the function is reachable as Array.getNonIndexStringProperties.

This preserves the practical benefit—supporting array‑likes and TypedArrays—albeit with slightly worse discoverability than placing it on Object.

Naming

The name is quite long, while it clearly reflects the intention. It should not matter to find an alternative, if that is deemed better, as long as the semantics stay the same.

Future Work

The length property is ignored as long as it is not enumerable, which is the case for arrays and typed arrays.

The regular expression exec/match/matchAll methods produce a "match object" that is an Array, with non-index string properties on it (lastIndex, groups, etc). All of these are enumerable and would be listed.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks