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

Accessing static private class parameters via this.constructor #48476

Closed
Araxeus opened this issue Mar 29, 2022 · 10 comments
Closed

Accessing static private class parameters via this.constructor #48476

Araxeus opened this issue Mar 29, 2022 · 10 comments

Comments

@Araxeus
Copy link

Araxeus commented Mar 29, 2022

Bug Report

🔎 Search Terms

access static private class parameter this.constructor

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about [static, private, classes]
    this probably has always been like this since its a 'new' feature

latest test on 4.7.0-dev.20220302 (nightly)

⏯ Playground Link

Playground link with relevant code

💻 Code

class Test {
    static #staticPrivateField = 'test' ;

    constructor() {
        console.log(
            this.constructor.#staticPrivateField
        )
    }
}

new Test();

🙁 Actual behavior

  1. in Javascript && Typescript (screenshot is .js file in vscode with no tsconfig)
    test.js

if the parameter is only static, it doesn't show the 6133 warning whether its actually used or not
the moment you make it both static + private (#), it suddenly shows the warning.

and then if the parameter is accessed via this.constructor it stills shows the 6133 warning (declared but value never read)

  1. strict check enabled (screenshot is .ts file)
    test.ts
    Property '#staticPrivateField' does not exist on type 'Function'.ts(2339)

🙂 Expected behavior

  1. in javascript using this.constructor.#staticPrivateField should be recognized as accessing the parameter (it does work, and recommended on MDN)
  2. strict check should recognize that this field exist on the class constructor
@MartinJohns
Copy link
Contributor

Duplicate of #32452.

@Jamesernator
Copy link

Jamesernator commented Mar 30, 2022

While .constructor is poorly typed at the moment, what you're describing doesn't in general work with subclassing anyway, and in most cases is probably indicative of a mistake:

class Class {
    static #field = 3;

    constructor() {
        console.log(this.constructor.#field);
    }
}

class Subclass extends Class {}

new Subclass(); // Error

If you're just wanting the field, better to just use Class.#field directly rather than accessing it via the instance.

@Araxeus
Copy link
Author

Araxeus commented Mar 30, 2022

@Jamesernator Thank you for your input/suggestion but this is still a bug
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static#calling_static_members_from_a_class_constructor_and_other_methods

I don't think this is exactly a duplicate of #32452 since this issue is about a specific bug with static+private modifiers, but you're welcome to close it if I'm wrong

@Jamesernator
Copy link

but this is still a bug

Ah yes the fact it's warning that the private field is never used I would say is a bug.

The fact this.constructor is typed as any rather than the same type as the constructor is what #32452 is about.

Although I still don't reccomend using this.constructor for static private fields basically ever. Public fields/methods makes more sense because those can be inherited and there may be actual reasons to do so, however private fields do not act like public ones (either static or instance).

Like static private fields are only installed on the class they're declared on, they are not inherited in any way which is why my above example causes a runtime error (because Subclass has no private field #field).

So while the fact there's a warning here is a TypeScript error, my reccomendation is that in spite of this you should be using Test.#staticPrivateField basically 100% of the time, because Test is literally the only object that will ever have the #staticPrivateField (its subclasses will not).

@Araxeus
Copy link
Author

Araxeus commented Mar 30, 2022

Ah yes the fact it's warning that the private field is never used I would say is a bug.

I originally planned to open this issue just about this (encountered in js file),
but while testing this issue in typescript I encountered the 2nd error (Property '#staticPrivateField' does not exist on type 'Function'.ts(2339))

Although I still don't reccomend using this.constructor for static private fields basically ever. Public fields/methods makes more sense because those can be inherited and there may be actual reasons to do so, however private fields do not act like public ones (either static or instance).

Like static private fields are only installed on the class they're declared on, they are not inherited in any way which is why my above example causes a runtime error (because Subclass has no private field #field).

the way I see it that's intended behavior, the field is 'private' and not 'protected'/'public', so it shouldn't be inherited
I want that error to happen, if someone tries to extend this class and use private fields from it,
(if I didn't want this behavior, I would use only static and not static+private)

so for my use case this.constructor is actually pretty relevant, but I completely understand your viewpoint

@MartinJohns
Copy link
Contributor

MartinJohns commented Mar 30, 2022

I encountered the 2nd error (Property '#staticPrivateField' does not exist on type 'Function'.ts(2339))

This is exactly what #32452 is about. The constructor is simply typed Function. It doesn't know about any static elements of your class.

@MartinJohns
Copy link
Contributor

MartinJohns commented Mar 30, 2022

if the parameter is only static, it doesn't show the 6133 warning whether its actually used or not
the moment you make it both static + private (#), it suddenly shows the warning.

And this is a duplicate of #27899. There's no assignment check for public static properties. The reasoning is that the static property can be initialized from anywhere in your code, and this does not apply to private fields.

@Araxeus
Copy link
Author

Araxeus commented Mar 30, 2022

Yes but the main bug here is the fact that the warning '#staticPrivateField' is declared but its value is never read.ts(6133) shows up even tho the value is read via this.constructor.#staticPrivateField

which isn't a duplicate right?

@MartinJohns
Copy link
Contributor

this.constructor.#staticPrivateField has no relevance, because this does not refer to your private field. This is a type error. TypeScript does not understand that this.constructor refers to your static class which has a #staticPrivateField property.

If this.constructor would refer to the correct type (which the issue is about), TypeScript would see that it has the #staticPrivateField and would see the usage.

@Araxeus
Copy link
Author

Araxeus commented Mar 30, 2022

ok gotcha closing this and leaving comment there (bumping since its like 3 years old)

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