{"id":20743073,"url":"https://github.com/aimingoo/protected-property","last_synced_at":"2025-10-08T19:16:51.557Z","repository":{"id":89039489,"uuid":"206697290","full_name":"aimingoo/protected-property","owner":"aimingoo","description":"The proposal is an enhancement of private property.","archived":false,"fork":false,"pushed_at":"2019-09-12T18:13:31.000Z","size":2648,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-11T12:38:15.867Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aimingoo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-09-06T02:33:35.000Z","updated_at":"2019-09-12T18:14:41.000Z","dependencies_parsed_at":"2023-03-04T18:00:16.370Z","dependency_job_id":null,"html_url":"https://github.com/aimingoo/protected-property","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/aimingoo/protected-property","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aimingoo%2Fprotected-property","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aimingoo%2Fprotected-property/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aimingoo%2Fprotected-property/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aimingoo%2Fprotected-property/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aimingoo","download_url":"https://codeload.github.com/aimingoo/protected-property/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aimingoo%2Fprotected-property/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273848365,"owners_count":25178902,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-06T02:00:13.247Z","response_time":2576,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T07:08:59.693Z","updated_at":"2025-10-08T19:16:46.535Z","avatar_url":"https://github.com/aimingoo.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Protected property\n\nThe proposal is an enhancement of private property of class and object literals.(@[here](https://github.com/aimingoo/private-property)).\n\nThe proposal will provide `protected` keyword and implementations in class definitions and has the following advantages:\n\n* Simple and prototype based\n* No new components and less changes. \n* Easy to implement and clean concept.\n\n\nThe proposal is not tc39 officailly now but implemented at [prepack-core with proposal-protected-property](https://github.com/aimingoo/prepack-core/tree/proposal-protected-property) ([@here](https://github.com/aimingoo/prepack-core/tree/proposal-protected-property)).\n\nYou could see more test case in this project ([@here](#testcases)).\n\n## Usage\n\n**1. How to declare *protected* properties in a class definition** \n\nThe usage of  keyword *protected* is same as private property definition,  for example:\n\n```java\n// define protected property in class\nclass f {\n    // protected property will be created at prototype\n    protected data = 100;\n    // protected property for class\n    protected static data = 200;\n    // declaration list (maybe)\n    protected x, y, z = 100;\n\n    ...\n}\n\n// define protected method and accessor in class\nclass f {\n    protected get data() { ... };\n    protected foo() { ... };\n \n    // for static ...\n    ... \n}\n\n// in object literal definition\n// (no support)\n```\n\n**2. How to access protected properties**\n\nIt is also same as private property access:\n\n```javascript\nclass MyClass {\n  protected x = 100;\n  foo() {\n    console.log(x); // accept in current class\n  }\n}\nclass MyClassEx extends MyClass {\n  foo() {\n    console.log(x); // accept in child class\n  }\n}\n```\n\n\n\n**3. How to solve identifier (property name) corrpution in child classes**\n\nIn some occasions, you will want to give an alias for an inherited protected property. \n\nyou can use `private as` syntax in child class:\n\n```java\nclass MyClass {\n  protected x = 100;\n}\n\nclass MyClassEx extends MyClass {\n  private x as y; // when you want access inherited protected property with a new identifier\n  foo(x) {\n    console.log(x); // yes, arguments-x\n    console.log(y); // alias of inhrited `x`\n  }\n}\n```\n\nAnd as a syntactic sugar,  you can also use *as* keyword to declare an alias for a defined private property:\n\n```java\nclass MyClass {\n  private x = 100;\n  private x as y;\n  foo() {\n    console.log(x); // nop!\n    console.log(y); // 100\n  }\n}\n```\n\n**4. Update visibility in child classes**\n\nOverride `protected` visibility in child class:\n\n```java\nclass MyClass {\n  private x = 100;\n}\n\nclass MyClassEx extends MyClass {\n  protected as x; // set `private` for inherited protected `x`\n}\n\nclass MyClassEx2 extends MyClassEx {\n  foo() {\n    consoel.log(x); // nop!\n  }\n}\n```\n\n\n\n## Syntax summary\n\n* Define visibility with `private` and `protected `keyword.\n\n  ```javascript\n  Example:\n    private x;\n  \n  Syntax:\n  \u003cprivate|protected\u003e [static] name [= value] [, …]\t\t\t\n  \u003cprivate|protected\u003e [static] [get | set] methodName ( argumentsList ) { … }\n  ```\n\n   \u003e NOTE: support async and generator.\n\n* Allow private member access in internal\n\n  ```javascript\n  Ex:\n    internal private x;\n  \n  \u003cinternal\u003e \u003cprivate|protected\u003e name [= value] [, …]\n  \u003cinternal\u003e \u003cprivate|protected\u003e [get | set] methodName ( argumentsList ) { … }\n  ```\n\n   \u003e NOTE: The scope for private is the current class. The one for protected properties include his child-classes.\n   \u003e\n   \u003e NOTE: The `internal` prefix can not support for `static` definition.\n\n* Use identifier to access private members\n\n  ```javascript\n  Ex:\n    x\n  \n  Identifier::\n    IdentifierName but not ReservedWord.\n  ```\n\n* Use internal scope reference for instances\n\n  ```javascript\n  Ex:\n    this[internal.x]\n  \n  object[\u003cinternal\u003e.name]\n  ```\n\n  \u003e NOTE: the reference is computed property for instance object of AClass.\n\u003e\n\u003eNOTE: the computed property name is propertyReference base on ***internal*** object. the latter is names map of internal member in AClass.\n\n* Create alias, will hide inheritance name that exists in current private scope\n\n  ```javascript\n  Ex:\n    private y as x;\n  \n  Syntax:\n  \u003cprivate|protected\u003e [static] \u003cparentProtectedName\u003e as \u003cnewlyName\u003e [= value];\n  \u003cprivate|protected\u003e [static] \u003cparentProtectedName\u003e as [get | set] methodName ( argumentsList ) { … }\n  ```\n\n  \u003e NOTE: the `parentProectedName` is inherited name from parent class.\n  \u003e\n  \u003e NOTE: maybe, the `private ... as` can support privated name in current scope.\n\n* Override visibility or internal access prefix for inherited protected property,  and/or update value\n\n  ```javascript\n  Ex:\n    private as x;\n  \n  Syntax:\n  [internal] \u003cprivate|protected\u003e [static] as \u003cparentProtectedName\u003e [= value];\n  [internal] \u003cprivate|protected\u003e [static] as [get | set] \u003cparentProtectedName\u003e( argumentsList ) { … }\n  ```\n\n  \u003e NOTE: internal access privilege will inherited for `protected` definition, you can reset it with `internal` prefix in child-classes base on `\u003cprivate|protected\u003e as` syntax.\n\n\n\n## Concepts\n\nThe protected property is object instance's private member too, it was defined only in class definition. private and protected is all of object's private scope/domain.\n\nIf a private member is protected, the member will be visible in current class and its all child-classes. For protected property, the orginal value, attributes of property descriptor, and internal access privilege are inherited too.\n\nA protected property can be overridden by any of its subclasses in the scope of the subclass. The items covered includes its value, visibility, and IAP privileges.\n\n\n\n## Implementation\n\n### Main processes\n\n**Core rules:**\n\n- not possible to access a private member of an object when his Class unaware. so,\n- not possible to directly access private scope outside of the Class declaration.\n\n**Key implementation steps:**\n\n- Set prototype of `AClass.prototype.[[Private]]` to its `[[Protected]]`, and set prototype of `[[Protected]]` to `ParentClass_Of_AClass.prototype.[[Protected]]`. The `[[Protected]]` internal slot of AClass and its parent-class similar to this.\n\nDone.\n\n### Syntax `as` implementation\n\n* function *setVisibleInScope(target, key)*\n\n  Let *unscopables* to be value of @@unscopables from symbol properties of *target*. set *unscopables*[*key*] to false.\n\n* function *setInvisibleInScope(target, key)*\n\n  Let *unscopables* to be value of @@unscopables from symbol properties of *target*. set *unscopables*[*key*] to true.\n\n\u003e Note: Visibility is managed by @@unscopable, and @@unscopable is also implemented based on the prototype inheritance chain of `[[Protected]]` of AClass.prototype or AClass.\n\u003e\n\u003e Note: The *targetObject* is **AClass** of static method definetion in class define, otherwise be **AClass.protoype**.\n\n#### syntax ` private as b`\n\n- in PropertyDefinitionEvaluation()\n\n  Let *downgrading* to be true when `b` protected and will set visibility to `private`, otherwise false.\n\n  Let *fromScope* to be *targetObject*.[[Protected]]. Let *toScope* to be *targetObject*.[[Private]] when *downgrading*, otherwise set *toScope* equ *fromScope*.\n\n  If `downgrading` is true, let *privateSymbol* to be private-key of name `b` from protected members by *fromScope*.\\[\\[Get\\]\\]() method, and create new property named `b` in *toScope* , set its value to be *privateSymbol*.\n\n  Call setInvisibleInScope(*fromScope*, 'b'), and call setVisibleInScope(*toScope*, 'b').\n\nDone.\n\n#### syntax private a as b\n\n- in PropertyDefinitionEvaluation()\n\n  Let *targetScope* to be *targetObject*.[[Protected]] for syntax `protected...`, otherwise set to *targetObject*.[[Private]].\n\n  Let *privateSymbol* to be private-key of name `a` from protected members by *targetObject*.\\[\\[Protected\\]\\].\\[\\[Get\\]\\]() method, and create new property named `b` in *targetScope*, set its value to be *privateSymbol*. \n\n  Call setInvisibleInScope(*targetScope*, 'a'), and call setVisibleInScope(*targetScope*, 'b'). \n\nDone.\n\n\u003e Note: Will be create new private member `b` when using syntax `private a as b`. The difference is update only visibility or IAP or value on existing `b` when using `private as b`.\n\n\n## Completed and planning\n\n- [x] Class definition\n- [x] protected property features\n  - [x] override visibility\n  - [x] private *\\\u003cparentProtectedName\\\u003e* as \\\u003c*alias*\\\u003e\n  - [x] (un)set internal access privilege\n- [ ] destructuring assignment (maybe)\n- [ ] declaration list (maybe)\n- [x] other same features of private property\n\n\n\n## FAQ\n\n* alias?\n\n  in child-classes, you know a protected name in parent but cant change it. and maybe you want access outer scope but impact with that name. for the case, you need set a alias for that name. ex:\n\n  ```javascript\n  var x = 100;\n  \n  class MyClass {\n    protected x = 200;\n  }\n  \n  class MyClassEx extends MyClass {\n    // I want access global-x, so set alias for protected-x\n    private x as xxx; // xxx in current private-scope only\n  \n    foo() {\n      console.log(x); // 100\n      console.log(xxx); // 200, inherited\n    }\n  }\n  ```\n\n\n\n## Testcases\n\nThe proposal has full test case in repository, current syntax based.\n\n```bash\n# install test framework\n\u003e mkdir node_modules\n\u003e npm install fancy-test chai mocha --no-save\n# test it\n\u003e mocha\n\n# (OR)\n\u003e bash run.sh\n```\n\n\n\n## References\n\n* [Objections to fields, especially the private field syntax](https://github.com/tc39/proposal-class-fields/issues/150)\n* [The proposal should be rejected!](https://github.com/tc39/proposal-class-fields/issues/148)\n* [My comments at #100](https://github.com/tc39/proposal-class-fields/issues/100#issuecomment-429533532)\n\n\n\n## History\n\n2019.09.06 draft-1 release.\n\n2019.08.22 initial release.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faimingoo%2Fprotected-property","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faimingoo%2Fprotected-property","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faimingoo%2Fprotected-property/lists"}