Skip to content
EcmaScript proposal to provide brand checks without exceptions
HTML
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitattributes Initial commit Feb 6, 2020
.gitignore Initial commit Feb 6, 2020
.npmrc Initial commit Feb 6, 2020
LICENSE Initial commit Feb 6, 2020
README.md Initial spec Feb 6, 2020
index.html spec: remove unneeded +In grammar parameter Feb 13, 2020
package.json Initial spec Feb 6, 2020
spec.emu spec: remove unneeded +In grammar parameter Feb 13, 2020

README.md

Ergonomic brand checks for Private Fields

EcmaScript Proposal, specs, and reference implementation to provide brand checks without exceptions.

Spec drafted by @ljharb.

Built on top of https://github.com/tc39/ecma262/pull/1668/ pending Class Fields being stage 4 and merged into the larger spec.

This proposal is currently at stage 0 of the process.

Rationale

Private fields have a built-in ”brand check”, in that if you try to access a private field on an object that does not have it installed, it throws an exception.

This is great! However, in order to keep the existence of a private field actually private, I often want to check if an object has a private field, and if not, have some fallback behavior (which might even be throwing a custom exception, with a message that does not reveal that I’m using a private field as my mechanism).

Using try/catch for this does work, but is quite awkward:

class C {
  #brand;

  static isC(obj) {
    try {
      obj.#brand;
      return true;
    } catch {
      return false;
    }
  }
}

What is desired is a simple solution to produce a boolean that does not require a try/catch or exceptions.

Possible Solutions:

in

The most obvious solution seems to be using the in keyword, like so:

class C {
  #brand;

  static isC(obj) {
    return #brand in obj;
  }
}

This has no ASI hazards I am aware of; however, it does have one important tradeoff: it permanently kills any possibility for private field shorthand. Specifically, this is because if #brand (in the previous example) is a shorthand for this.#brand, then (#brand) in obj would have to mean the same as this.#brand in obj, which means "is the value of this.#brand in obj?", not "does obj have the private field #brand?".

try statement

Another alternative is:

class C {
  #brand;

  static isC(obj) {
    return try obj.#brand;
  }
}

However, this strongly suggests that try <expression> would be a generic syntax for "if it throws an exception, produce false, otherwise produce true". That would be a much larger proposal, and would perhaps be a bit overkill to solve the specific problem around private fields.

This would require a lookahead restriction for a curly brace (which would mean that the try expression couldn't be an object literal, unless it was wrapped in parens).

Spec

You can view the spec for the in solution rendered as HTML.

You can’t perform that action at this time.