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

Class property readonly? for external consumers #53707

Closed
5 tasks done
streamich opened this issue Apr 9, 2023 · 5 comments
Closed
5 tasks done

Class property readonly? for external consumers #53707

streamich opened this issue Apr 9, 2023 · 5 comments

Comments

@streamich
Copy link

streamich commented Apr 9, 2023

Suggestion

Add ability to specify that some class property is read-only for users outside the class, but it should still be writable by the code within the class.

This behaviour can be achieved with getters and setter, but: (1) it is very verbose; (2) and there is performance penalty.

class A {
  #__foo: string;

  public get foo(): string {
    return this.#__foo;
  }
}

Instead, would be nice if this behaviour could be achieved with a single line of code:

class A {
  public readonly? foo: string;
}

Note ? in readonly?. The ? could indicate a new flavor of readonly keyword, which makes the property read-only for external users, but still writable for code inside the class.

✅ Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

I see there could be two implementation approaches.

Option 1: No runtime changes, only type checking

Here the compiler would emit the same JavaScript code as if the readonly? keyword was not present. The only difference would be errors in TypeScript, if somebody tries to modify the property from outside the class.

Option 2: Enforcing it

TypeScript could rewrite the property to enforce it being read-only from outside the class, but still writable from within the class.

This TypeScript code:

class A {
  public readonly? foo: string = '';
}

Would result in JavaScript like this:

class A {
  constructor() {
    this.#$$foo = '';
  }
  
  get foo() {
    return this.#$$foo;
  }
}

💻 Use Cases

Consider this controllable Promise class—Defer, to avoid getter/setter performance penalty and still have TypeScript's readonly annotation, one needs to cast this to any.

export class Defer<T> {
  public readonly resolve!: (data: T) => void;
  public readonly reject!: (error: any) => void;
  public readonly promise: Promise<T> = new Promise<T>((resolve, reject) => {
    (this as any).resolve = resolve;
    (this as any).reject = reject;
  });
}

With the proposed change, the code would change to

export class Defer<T> {
  public readonly? resolve!: (data: T) => void;
  public readonly? reject!: (error: any) => void;
  public readonly promise: Promise<T> = new Promise<T>((resolve, reject) => {
    this.resolve = resolve;
    this.reject = reject;
  });
}
@fatcerberus
Copy link

I'm like 99% sure this is a dupe but I can't seem to find the other issue now.

For the record though, option 2 (runtime enforcement) is untenable:

This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)

Emitting different code based on the presence of readonly? would be type-directed emit which is something TS actively avoids doing, by design.

@MartinJohns
Copy link
Contributor

Duplicate of #37487.

@fatcerberus
Copy link

@MartinJohns How did you find that? I was certain that issue existed but I tried searching for various permutations of public private protected readonly and it eluded me every time. 😄

@MartinJohns
Copy link
Contributor

@fatcerberus I searched for writable in:title. Wasn't totally sure about what term to search for, but I knew the issue existed (I saw it before). Especially the in:title is super helpful when searching, it weeds out so many issues where the keyword is just coincidentally mentioned.

@streamich
Copy link
Author

Closing it as it is a duplicate of #37487

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants