Skip to content
Private Declarations Proposal at Stage 1
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
README.md

README.md

Private Declarations

A Stage 1 proposal to add Private Declarations, allowing trusted code outside of the class lexical scope to access private state.

private #hello;
class Example {
  [#hello] = 'world!';
}

const ex = new Example();
console.log(ex.#hello);
// => 'world!'

Guiding Use Cases

"Protected" state

Protected state is a valuable visibility state when implementing class hierarchies. For for instance, a hook pattern might be used to allow subclasses to override code:

// https://github.com/Polymer/lit-html/blob/1a51eb54/src/lib/parts.ts

private #createPart;

class AttributeCommitter {
  //...

  [#createPart]() {
    return new AttributePart(this);
  }
}

class PropertyCommitter extends AttributeCommitter {
  [#createPart]() {
    return new PropertyPart(this);
  }
}

Here, both AttributeCommitter explicitly allows trusted (written in the same source file) subclasses to override the behavior of the #createPart method. By default, a normal AttributePart is return. But PropertyCommitter works only on properties and would return a PropertyPart. All other code is free to be inherited via normal publicly visible fields/methods from AttributeCommitter.

Note that this does not privilege code outside the file to override the #createPart method, the #createPart declaration is visible only to the file.

Friend classes/functions

For prior art in C++, see https://en.wikipedia.org/wiki/Friend_function.

The AMP Project has a particular staged linting pattern that works well with friendly functions that guards access to restricted code. To begin with, statically used functions are considerably easier to lint for than object-scoped method calls because we do not need to know the objects type to determine if this is a restricted call or just a non-restricted call that uses the same method name. Eg, it's easier to tell that a static export registerExtendedTemplate is restricted vs obj.registerExtendedTemplate.

// https://github.com/ampproject/amphtml/blob/18baa9da/src/service/template-impl.js

private #registerTemplate;

// Exported so that it may be intalled on the globally and shared
// across split bundles.
export class Templates {
  [#registerTemplate]() {
    //...
  }
}

// The code privileged to register templates with the shared class
// instance. Importing and using is statically analyzable, and must pass
// a linter.
export function registerExtendedTemplate() {
  const templatesService = getService('templates');
  return templatesService.#registerTemplate(...arguments);
}
You can’t perform that action at this time.