-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Bug: Accessing private statics in a class via its derived class is allowed #8624
Comments
What's the motivation? |
@Elephant-Vessel not sure what you mean. This is incorrect behavior, yes? |
I'm just curious about why this would be regarded as incorrect behavior. This works for example fine in C#, why would it be incorrect in the context of TypeScript? |
looking at this again, i is not a bug. it behaves as intended. see https://github.com/Microsoft/TypeScript/blob/master/doc/spec.md#822-accessibility
the private property |
Interesting. I disagree with both the TypeScript and C# spec in that accessing a member (static or otherwise) of an item implies that it's a publicly available property of that item. But, if you & the other spec writers believe otherwise, looks like the issue ends here. @Elephant-Vessel this behavior was flagged when enabling the |
Funny enough I actually encountered a bug caused by this behavior today. class FooBase {
private static privateStatic: string = "unset";
testPrivateStatic(): void {
Foo.privateStatic = "set";
console.log(FooBase.privateStatic);
}
}
class Foo extends FooBase { }
// Logs "unset" but you'd expect it to log "set"
new FooBase().testPrivateStatic(); @mhegazy, I think the spec should be changed. Does this change your mind? :) |
in dead. reopening. |
Yeah, that behavior don't make much sense. I think it's quite strange that derived classes clone static fields from the base class, regardless whether one should be able to access |
the copying is by design. witnessing an invalid state is what this issue tracks. |
Is there anywhere one could read about that design desision? Just out of interest. |
Agree that you should not be able to access derived class private statics through their name |
PRs are welcomed |
That's not private static member access by a derived class because the On Wed, Aug 10, 2016 at 1:47 PM, Elephant-Vessel notifications@github.com
|
@jnm2 Yes. To be specific, it's by the base class via the derived class. |
@jnm2 Sorry for making noise, I did not see that you removed your comment before I replied. However, yes I agree, this behavior would be strange considering that TypeScript is copying the static members down the inheritance chain. I was not aware of that, but I think that this copying is even stranger, from a consumer point-of-view. Or who knows, maybe it's just a feature that I have yet to discover the value of... |
Instead of copying, what would be wrong with compiling If you want two copies of a static member for some reason, I would assume you would want to declare each copy since this is a statically typed language. |
Thinking about this some more, I kinda get excited about static inheritance since classes are first-class entities in typescript. It's not very relevant in languages like Java or C# where classes are not first-class entities, but why not in TS? It feels like it could have some neat expressive power. However, this bugs me: class Animal {
public static Sound() {
console.log("animal class")
}
public Color() {
console.log("Unknown")
}
}
class Dog extends Animal {
}
var test = typeof Animal;
Animal.Sound = () => console.log("mutated class") // Mutating static metod
Animal.prototype.Color = () => console.log("mutated color") // Mutating prototype method
Dog.Sound(); // => "animal class" : Hmm.... Grumpy face.
Animal.Sound(); // => "mutated class"
new Dog().Color(); // => "mutated color"
new Animal().Color(); // => "mutated color" If static inheritance could be considered a feature, maybe it would benefit from behaving more like regular inheritance. In the above example, it could theoretically be solved if Dog by default (not having any method overrides) would be compiled like this: class Dog extends Animal
{
public static Sound(){
super.Sound();
}
} Then it would behave the same as regular inheritance. And regarding Joshuas bug above, if it was compiled to something like this, there would be no problem: class FooBase {
static privateStatic: string = "unset";
testPrivateStatic(): void {
Foo.privateStatic = "set";
console.log(FooBase.privateStatic);
}
}
class Foo extends FooBase {
static get privateStatic(){
return super.privateStatic;
}
static set privateStatic(value){
super.privateStatic = value;
}
}
// Now logs set
new FooBase().testPrivateStatic(); |
Just my 2 cents. |
But classes are objects in TS. This is a very important distinction from languages like C# and Java, in TS you can handle classes just like any other objects. You can put classes in a set and iterate it and call their static methods: type Component =
{
RegisterComponent: () => void;
}
class FooViewComponent
{
public static RegisterComponent= () => { /* ... */ }
}
class BarViewComponent
{
public static RegisterComponent= () => { /* ... */ }
}
function SetUpApplication()
{
var components:Component[] = [FooViewComponent, BarViewComponent];
components.forEach((component) => component.RegisterComponent());
} If typescript embraced static inheritance, it could look like this: interface Component
{
static RegisterComponent: () => void;
}
class ButtonComponent implements Component
{
public static RegisterComponent= () => { /* ... */ }
}
class SuperButtonComponent extends ButtonComponent
{
//...
}
function SetUpApplication()
{
var components:Component[] = [ButtonComponent , SuperButtonComponent ];
components.forEach((component) => component.RegisterComponent());
} Of course you can solve the same behavior in other ways, but I think this would be really neat and expressive in TS once you slightly adjust the mental model of the class that you got from C#/Java and embrace more expressive possibilities. |
If we eventually get some breaking change regarding privates here, maybe we could do two birds at once and remove the general access to privates in a T from within any T, #471, giving us better encapsulation in the language? |
TypeScript Version:
1.8.X
Code
Expected behavior:
Accessing
Foo.privateStatic
shouldn't be allowed, regardless of the context it's called in.Actual behavior:
FooBase
is allowed to do this.(thanks @sethbrenith for deducing this)
The text was updated successfully, but these errors were encountered: