Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggestion: a streamlined way to "expose" private variables publically #11804

Closed
JoshuaKGoldberg opened this issue Oct 23, 2016 · 6 comments
Closed
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds

Comments

@JoshuaKGoldberg
Copy link
Contributor

JoshuaKGoldberg commented Oct 23, 2016

Right now, if you want to expose a class property with a public getter and a private setter, the standard a possibility is to use methods (since gets and sets can't have different visibility):

class Container<T> {
    private value: T;

    constructor(value: T) {
        this.value = value;
    }

    public getValue(): T {
        return this.value;
    }
}
// To access the value
new Container("foo").getValue(); // "foo"

The code works fine, but with a caveat: there's an extra function defined for every exposure. That really bloats the generated JavaScript.

Edit: the same holds true for creating a getter. See the second and third comments.

I propose some sort of exposure functionality be added for these simple private values. They should still be publicly gettable but only privately settable.

A few options would be to mix public and private, create a new exposed keyword, or use a variation C#'s { get; private set; }

class Container {
    public private value: T;
    private exposed value: T;
    public value: T { get; private set; }
    // ...
}
new Container("foo").value; // "foo"

I slightly prefer the keyword approaches, since in C# there's a difference between properties and fields, and using the property syntax on TypeScript fields could be viewed as a syntactic conflation with the existing get/set properties.

Note that there are prior, mostly-declined issues vaguely related to this. #2845 is the closest by asking for different access modifiers for getter and setter. I think this is a better approach for simulating C#'s { get; private set; }

This is also different from the readonly and imm proposals. The goal here is to allow changing the property with less code. Arguably, allowing the language to prefer directly accessing properties actually embraces the third and fourth design goals by removing the need to rely on methods to guarantee property privacy and creating more streamlined output JavaScript.

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Oct 23, 2016

Right now, if you want to expose a class property with a public getter and a private setter, the standard is to use methods (since gets and sets can't have different visibility):

  class Container<T> {
      private value: T;

      constructor(value: T) {
          this.value = value;
      }

      public getValue(): T {
          return this.value;
      }
  }

The standard approach is to use a getter.

  class Container<T> {
      private _value: T;

      constructor(value: T) {
          this._value = value;
      }

      get value() {
          return this._value;
      }
  }

new Container("foo").value; // "foo"

@JoshuaKGoldberg
Copy link
Contributor Author

JoshuaKGoldberg commented Oct 23, 2016

@aluanhaddad yes, and using a getter results in significantly more generated JavaScript on lower ES targets. The point of this proposal is to not have to do that.

Without a getter:

var Container = (function () {
    function Container(value) {
        this._value = value;
    }
    return Container;
}());

With a getter:

var Container = (function () {
    function Container(value) {
        this._value = value;
    }
    Object.defineProperty(Container.prototype, "value", {
        get: function () {
            return this._value;
        },
        enumerable: true,
        configurable: true
    });
    return Container;
}());

Creating a getter is a bit of extra work that I don't think should be necessary for this type of behavior.

Edit: But yes, it would have been better for me to write "a possibility" instead of "a standard".

@JoshuaKGoldberg JoshuaKGoldberg changed the title Suggestion: a way to "expose" private variables publically Suggestion: a streamlined way to "expose" private variables publically Oct 23, 2016
@aluanhaddad
Copy link
Contributor

@JoshuaKGoldberg Indeed there is more emitted code but performance in es5.1 environments should be quite good.

@mhegazy
Copy link
Contributor

mhegazy commented Oct 24, 2016

What you are missing are two modifiers, private_set and protected_set that can adorn a property. you can combine them with public and protected to get public|protected read, private|protected write properties. (assuming public private_get is not really a scenario that is worth supporting). in this context, readonly is just an alias for constructor_set.

@mhegazy mhegazy added Suggestion An idea for TypeScript In Discussion Not yet reached consensus labels Oct 24, 2016
@JoshuaKGoldberg
Copy link
Contributor Author

Looks like the team is collectively not in favor of adding new keywords for this. That makes sense. How about combining existing privacy keywords?

  • If there is one keyword, both gets and sets use it
  • If there are two keywords, gets use the first and sets use the second
  • The first keyword must be strictly more "open" than the second
class AllowedMemberPrivacySettings<T> {
    public fullyPublic: T;
    public protected publicGetsProtectedSets: T;
    public private publicGetsPrivateSets: T;
    protected fullyProtected: T;
    protected private protectedGetsPrivateSets: T;
    private fullyPrivate: T;
}

The public protected/public private combo could be particularly useful for MobX stores in MobX's strict mode:

import { action, observable } from "mobx";

class Store<T> {
    @observable
    public private data: T;

    @action
    public setData(data: T): void {
        this.data = data;
    }
}

@RyanCavanaugh RyanCavanaugh added Too Complex An issue which adding support for may be too complex for the value it adds and removed In Discussion Not yet reached consensus labels Aug 12, 2017
@RyanCavanaugh
Copy link
Member

This falls victim to the same problem as others - we don't distinguish the type of a property for reading vs the type/accessibility of it for writing, so the variance problems become rather hairy and you'd quickly find yourself doing unsound writes or reads.

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Suggestion An idea for TypeScript Too Complex An issue which adding support for may be too complex for the value it adds
Projects
None yet
Development

No branches or pull requests

4 participants