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

Ability to reference typeof hashed private field #48090

Closed
5 tasks done
JacobLey opened this issue Mar 2, 2022 · 4 comments
Closed
5 tasks done

Ability to reference typeof hashed private field #48090

JacobLey opened this issue Mar 2, 2022 · 4 comments

Comments

@JacobLey
Copy link

JacobLey commented Mar 2, 2022

Suggestion

πŸ” Search Terms

hash private type reference # namespace exist

βœ… 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

(To my knowledge) it is not possible to reference the type of a hashed private field, the same way you might reference a privately declared field.

Either enabling this syntax, or providing some intrinstic wrapper to access the type would be helpful in DRYing up code using hashed private fields.

Suggested syntaxes:

  • Foo.#attrName
  • PrivateHash<Foo, 'attrName'>

To be clear, my request is only to access the type of hashed private fields. The actual output JS and handling of hashed private fields should remain unchanged. Any newly supported syntax should be stripped out at transpile time.

πŸ“ƒ Motivating Example

Consider the following TS declaration of a class using two, differently declared private fields

class Person {

   private _firstName: string;
   #lastName: string;

   constructor(firstName: string, lastName: string) {
       this._firstName = firstName;
       this.#lastName = lastName;
   }

   sayHello() {
      return `Hello ${this._firstName} ${this.#lastName}`;
   }
}

This is currently valid typescript and is fully supported.

In some cases, it may be that "names" aren't only strings. Perhaps they can be complicated types such as string | null | () => string | NameClass | .... In such cases, it is convenient to write that union once, and reference it.

For typescripts private declarations, that is supported, but not for JS's hashed private fields.

class Person {

   private _firstName: string | null | undefined | NameClass | some | complicated | union | of | types;
   #lastName: string | null | undefined | NameClass | some | other | and | different | union | of | types;

   constructor(
       firstName: Person['_firstName'], 
       // FAILS WITH TYPESCRIPT
       lastName: Person.#lastName, // OR PrivateHash<Person, 'lastName'> OR Person['#lastName']
   ) {
       this._firstName = firstName;
       this.#lastName = lastName;
   }
}

πŸ’» Use Cases

This feature is primarily one of convenience, attempting to achieve "feature parity" with Typescripts private fields.

If the goal is to only write the type once (DRY) then the best workaround, for now, is to declare a type/interface and reference that in both the attribute declaration and usages. Arguably that makes the attribute itself not the "source of truth" for it's own type.

type ComplicatedName = string | null | undefined | NameClass | some | other | and | different | union | of | types;
class Person {
    #lastName: ComplicatedName;
   constructor(lastName: CompicatedName) {
       this.#lastName = lastName;
   }
}

# prefixed fields are actually a JS feature, and therefore usage is restricted in ways that typescript cannot control. In the example above, it is possible to reference the type outside the class as well:

const person = new Person('Joe', 'Schmoe'); 

// Legal in TS + JS
type FirstName = typeof person['_firstName'];
const firstName = person['_firstName'];

// Illegal in TS + JS
type LastName = typeof person.#lastName;
const lastName = person.#lastName;

In this case, I would be fine with TS disabling access (i.e. do not apply this feature request) to hashed private fields outside of the class itself, to mirror actual usage.

@fatcerberus
Copy link

fatcerberus commented Mar 2, 2022

For the record, Class['prop'] doesn't work either when the property is marked private.

Nevermind, I was wrong, there was just a typo (missing underscore) in your second code block.

@JacobLey
Copy link
Author

JacobLey commented Mar 2, 2022

Updated code block to match _ prefix.

Worth noting the _ prefix is just a naming pattern to help indicate private. It is irrelevant to the actual functionality of typescript private vs hashed private fields

@xiBread
Copy link

xiBread commented Mar 3, 2022

Duplicate of #47595, fixed in #47696

@JacobLey
Copy link
Author

JacobLey commented Mar 3, 2022

Thank you! That is mostly what I am looking for.

Although typeof this is not supported in constructors, which is why I was running into the issue.

Probably good enough for my use case though...

@JacobLey JacobLey closed this as completed Mar 3, 2022
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