Skip to content

Allow Type Extraction and/or Access from # Private Fields and Methods in TypeScript Classes #61397

@Elidor00

Description

@Elidor00

🔍 Search Terms

private field, private modifier, type definition, class properties, type inference

✅ Viability Checklist

⭐ Suggestion

With the widespread use of # private fields and methods in TypeScript, it is no longer possible to define or access the types of private class properties or methods. Using the private modifier, class properties could be referenced in type definitions, but this is no longer the case with # private fields. Introducing a way to leverage private fields and methods for type definition purposes would be highly beneficial.

📃 Motivating Example

This feature was useful for defining types based on class properties or methods without exposing them publicly. The lack of this capability with # private fields limits the flexibility of type inference in certain scenarios.

class Test {
  #a = 3;

  private a = 4;

  private method(): Test['a'] { // it works
    return this.a;
  }

  #method(): Test['#a'] { // it doesn't work
    return this.#a;
  }
}

export type WorkingType = Test['method']; // it works
export type NotWorkingType = Test['#method']; // it doesn't work

This feature was useful for defining types based on class properties or methods. For example in our scenarios defining types using return types of internal generator/factory methods.

export type A = ReturnType<Test['method']>; // it works
export type B = ReturnType<Test['#method']>; // it doesn't work

💻 Use Cases

What do you want to use this for?
In our scenarios we create an internal method that generates a complex value and we want to use its return type to define a public property of the same class. To achieve this we need to access the method’s return type from within the class scope. Additionally, we would to expose this type.
This could be done using the property’s type (because the property is public), but so far we have always accessed it using the return type of the private method, as shown in the following example.

class Test {
  public property: PropertyType | null = null;

  // the return type is inferenced
  private propertyGenerator() { 
    return 1;
  }

  // somewhere in the code
  // this.property = this.propertyGenerator();
}

export type PropertyType = ReturnType<Test['propertyGenerator']>;

Our desiderata:

Option 1:
True private (#) method type is accessible like the private (modifier) method type.

class Test {
  public property: PropertyType | null = null;

  #propertyGenerator() { 
    return 1;
  }
}

export type PropertyType = ReturnType<Test['#propertyGenerator']>;

Option 2:
True private (#) method type is accessible inside its class.

class Test {
  public property: ReturnType<Test['#propertyGenerator']> | null = null; // Property '#propertyGenerator' does not exist on type 'Test'.

  #propertyGenerator() { 
    return 1;
  }
}

export type PropertyType = Test['property'];

What shortcomings exist with current approaches?
The main issue is that we can use the private methods and fields of the class inside the class scope, but we cannot use their types in the same way and in the same scope. In addition, avoiding # means losing all the advantages it provides over private.

What workarounds are you using in the meantime?
Currently, the only way to achieve similar behavior is by either making fields/method private, without using #, but by doing this you lose all the advantages of using the # instead of private.
An alternative, is to define the type by hand.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions